6.6.3 - Alpha4 - 意图相关操作 (编辑/查看/安装/发送/播放等) 增加操作异常提示

This commit is contained in:
SuperMonster003
2025-05-15 16:26:46 +08:00
parent d3a9cd0f26
commit 0882cf4166
37 changed files with 361 additions and 89 deletions

View File

@@ -33,6 +33,7 @@
* `优化` 设置页面对话框相关设置支持 "使用默认值" 菜单选项
* `优化` 文件管理器浮动按钮展开后点击其他区域可自动隐藏
* `优化` 打包单文件时自动读取并勾选已安装应用的声明权限 _[`issue #362`](http://issues.autojs6.com/362)_
* `优化` 意图相关操作 (编辑/查看/安装/发送/播放等) 增加操作异常提示
* `优化` 已忽略更新记录及客户端模式连接地址记录支持清空操作
* `优化` 版本更新信息支持多语言显示 (与当前显示语言同步)
* `优化` 使用异步加载方式一定程度提升文件管理器列表滑动流畅性

View File

@@ -33,6 +33,7 @@
* `优化` 设置页面对话框相关设置支持 "使用默认值" 菜单选项
* `优化` 文件管理器浮动按钮展开后点击其他区域可自动隐藏
* `优化` 打包单文件时自动读取并勾选已安装应用的声明权限 _[`issue #362`](http://issues.autojs6.com/362)_
* `优化` 意图相关操作 (编辑/查看/安装/发送/播放等) 增加操作异常提示
* `优化` 已忽略更新记录及客户端模式连接地址记录支持清空操作
* `优化` 版本更新信息支持多语言显示 (与当前显示语言同步)
* `优化` 使用异步加载方式一定程度提升文件管理器列表滑动流畅性

View File

@@ -1,14 +1,18 @@
package org.autojs.autojs.model.explorer;
import android.content.Context;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.autojs.autojs.external.fileprovider.AppFileProvider;
import org.autojs.autojs.model.script.ScriptFile;
import org.autojs.autojs.runtime.api.Mime;
import org.autojs.autojs.util.FileUtils;
import org.autojs.autojs.util.IntentUtils;
import org.autojs.autojs.util.IntentUtils.SnackExceptionHolder;
import org.autojs.autojs.util.IntentUtils.ToastExceptionHolder;
import org.autojs.autojs6.R;
import org.jetbrains.annotations.NotNull;
public interface ExplorerItem {
@@ -64,11 +68,37 @@ public interface ExplorerItem {
return getType().isMediaMenu();
}
default void install(Context context) {
IntentUtils.installApk(context, getPath());
default boolean install(@NotNull View view) {
return IntentUtils.installApk(view.getContext(), getPath(), AppFileProvider.AUTHORITY, new SnackExceptionHolder(view));
}
default void play(Context context) {
default boolean install(Context context) {
return IntentUtils.installApk(context, getPath(), AppFileProvider.AUTHORITY, new ToastExceptionHolder(context));
}
default boolean play(@NotNull View view) {
String mimeType = determineMimeTypeForPlay();
return IntentUtils.viewFile(
view.getContext(),
getPath(),
mimeType,
AppFileProvider.AUTHORITY,
new SnackExceptionHolder(view, R.string.error_no_applications_available_for_playing_this_file)
);
}
default boolean play(Context context) {
String mimeType = determineMimeTypeForPlay();
return IntentUtils.viewFile(
context,
getPath(),
mimeType,
AppFileProvider.AUTHORITY,
new ToastExceptionHolder(context, R.string.error_no_applications_available_for_playing_this_file)
);
}
private @NotNull String determineMimeTypeForPlay() {
String mimeType;
FileUtils.TypeData typeData = getType().getTypeData();
if (typeData == FileUtils.TypeDataHolder.INSTANCE.getVIDEO() || typeData == FileUtils.TypeDataHolder.INSTANCE.getVIDEO_PLAYLIST()) {
@@ -78,11 +108,23 @@ public interface ExplorerItem {
} else {
mimeType = Mime.WILDCARD;
}
IntentUtils.viewFile(context, getPath(), mimeType, AppFileProvider.AUTHORITY);
return mimeType;
}
default void view(Context context) {
IntentUtils.viewFile(context, getPath(), Mime.WILDCARD, AppFileProvider.AUTHORITY);
default boolean view(@NotNull View view) {
return IntentUtils.viewFile(view.getContext(), getPath(), null, AppFileProvider.AUTHORITY, new SnackExceptionHolder(view));
}
default boolean view(Context context) {
return IntentUtils.viewFile(context, getPath(), null, AppFileProvider.AUTHORITY, new ToastExceptionHolder(context));
}
default boolean edit(@NotNull View view) {
return IntentUtils.editFile(view.getContext(), getPath(), AppFileProvider.AUTHORITY, new SnackExceptionHolder(view));
}
default boolean edit(Context context) {
return IntentUtils.editFile(context, getPath(), AppFileProvider.AUTHORITY, new ToastExceptionHolder(context));
}
}

View File

@@ -17,6 +17,7 @@ import org.autojs.autojs.script.ScriptSource
import org.autojs.autojs.ui.edit.EditActivity
import org.autojs.autojs.util.FileUtils
import org.autojs.autojs.util.IntentUtils
import org.autojs.autojs.util.IntentUtils.ToastExceptionHolder
import org.autojs.autojs.util.ViewUtils
import org.autojs.autojs.util.WorkingDirectoryUtils
import org.autojs.autojs6.R
@@ -77,7 +78,13 @@ object Scripts {
@JvmStatic
fun openByOtherApps(uri: Uri) {
IntentUtils.viewFile(globalAppContext, uri, "text/plain", AppFileProvider.AUTHORITY)
IntentUtils.viewFile(
globalAppContext,
uri,
"text/plain",
AppFileProvider.AUTHORITY,
ToastExceptionHolder(globalAppContext),
)
}
@JvmStatic
@@ -159,15 +166,12 @@ object Scripts {
@JvmStatic
fun send(context: Context, file: ScriptFile) {
Intent(Intent.ACTION_SEND)
.setType("text/plain")
.putExtra(
Intent.EXTRA_STREAM,
IntentUtils.getUriOfFile(context, file.path, AppFileProvider.AUTHORITY)
)
.let { Intent.createChooser(it, context.getString(R.string.text_send)) }
.apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
.let { context.startActivity(it) }
IntentUtils.sendFile(
context,
file.path,
AppFileProvider.AUTHORITY,
ToastExceptionHolder(context),
)
}
}

View File

@@ -23,6 +23,7 @@ import org.autojs.autojs.annotation.Lazy;
import org.autojs.autojs.core.pref.Language;
import org.autojs.autojs.core.pref.Pref;
import org.autojs.autojs.core.ui.widget.CustomSnackbar;
import org.autojs.autojs.external.fileprovider.AppFileProvider;
import org.autojs.autojs.network.api.StreamingUrlApi;
import org.autojs.autojs.network.download.DownloadManager;
import org.autojs.autojs.network.entity.ExtendedVersionInfo;
@@ -31,6 +32,7 @@ import org.autojs.autojs.tool.SimpleObserver;
import org.autojs.autojs.ui.settings.DisplayVersionHistoriesActivity;
import org.autojs.autojs.util.AndroidUtils;
import org.autojs.autojs.util.IntentUtils;
import org.autojs.autojs.util.IntentUtils.ToastExceptionHolder;
import org.autojs.autojs.util.TextUtils;
import org.autojs.autojs.util.UpdateUtils;
import org.autojs.autojs.util.ViewUtils;
@@ -241,7 +243,12 @@ public class UpdateChecker {
private void download(Context context, VersionInfo versionInfo) {
Consumer<File> onNext = file -> {
mUpdateDialog = null;
IntentUtils.installApk(context, file.getPath());
IntentUtils.installApk(
context,
file.getPath(),
AppFileProvider.AUTHORITY,
new ToastExceptionHolder(context)
);
};
Consumer<Throwable> onError = e -> {

View File

@@ -5,11 +5,14 @@ import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.*
import android.content.pm.PackageManager.ApplicationInfoFlags
import android.content.pm.PackageManager.GET_META_DATA
import android.content.pm.PackageManager.NameNotFoundException
import android.content.pm.PackageManager.PackageInfoFlags
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.core.net.toUri
import org.autojs.autojs.annotation.ScriptInterface
import org.autojs.autojs.app.GlobalAppContext
import org.autojs.autojs.external.fileprovider.AppFileProvider
@@ -33,7 +36,7 @@ import org.autojs.autojs.runtime.api.augment.app.App as AugmentableApp
* Created by Stardust on Apr 2, 2017.
* Modified by SuperMonster003 as of Jul 13, 2022.
*/
class AppUtils(context: Context, @get:ScriptInterface val fileProviderAuthority: String? = AppFileProvider.AUTHORITY) {
class AppUtils(context: Context, @get:ScriptInterface val fileProviderAuthority: String = AppFileProvider.AUTHORITY) {
private val mContext: Context = context
private val mPackageManager = mContext.packageManager
@@ -155,16 +158,27 @@ class AppUtils(context: Context, @get:ScriptInterface val fileProviderAuthority:
@ScriptInterface
fun uninstall(packageName: String) {
Intent(Intent.ACTION_DELETE, Uri.parse("package:$packageName"))
Intent(Intent.ACTION_DELETE, "package:$packageName".toUri())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.let { mContext.startActivity(it) }
}
@ScriptInterface
fun viewFile(path: String) = IntentUtils.viewFile(mContext, path, fileProviderAuthority)
fun viewFile(path: String) = IntentUtils.viewFile(
context = mContext,
path = path,
mimeType = null,
fileProviderAuthority = fileProviderAuthority,
exceptionHolder = IntentUtils.ToastExceptionHolder(mContext),
)
@ScriptInterface
fun editFile(path: String) = IntentUtils.editFile(mContext, path, fileProviderAuthority)
fun editFile(path: String) = IntentUtils.editFile(
context = mContext,
path = path,
fileProviderAuthority = fileProviderAuthority,
exceptionHolder = IntentUtils.ToastExceptionHolder(mContext),
)
@ScriptInterface
fun openUrl(url: String) {

View File

@@ -11,6 +11,7 @@ import android.graphics.Paint;
import android.media.Image;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Base64;
import android.util.Log;
import android.view.Gravity;
@@ -190,7 +191,7 @@ public class Images {
public ScriptPromiseAdapter requestScreenCapture(int orientation, int width, int height, boolean isAsync) {
ScriptPromiseAdapter promiseAdapter = new ScriptPromiseAdapter();
if (mScreenCapturer == null) {
Handler handler = isAsync ? new Handler() : new Handler(mScriptRuntime.loopers.getServantLooper());
Handler handler = isAsync ? new Handler(Looper.getMainLooper()) : new Handler(mScriptRuntime.loopers.getServantLooper());
Context contextForRequest = mScriptRuntime.app.getCurrentActivity();
if (contextForRequest == null) contextForRequest = mContext;
mScreenCaptureRequester = new ScreenCaptureRequester();

View File

@@ -23,6 +23,7 @@ import org.autojs.autojs.ui.project.BuildActivity;
import org.autojs.autojs.util.ClipboardUtils;
import org.autojs.autojs.util.ConsoleUtils;
import org.autojs.autojs.util.IntentUtils;
import org.autojs.autojs.util.IntentUtils.ToastExceptionHolder;
import org.autojs.autojs.util.ViewUtils;
import org.autojs.autojs6.R;
@@ -198,7 +199,11 @@ public class EditorMenu {
var executionInfo = JavaScriptFileSource.parseExecutionMode(mEditor.getText());
mEditor.insert(executionInfo.getLineno(), item.getImportText() + ";\n");
})
.onNeutral((ignored, which) -> IntentUtils.browse(mContext, item.getUrl()))
.onNeutral((ignored, which) -> IntentUtils.browse(
mContext,
item.getUrl(),
new ToastExceptionHolder(mContext)
))
.onAny((ignored, which) -> dialog.dismiss())
.show();
}

View File

@@ -21,7 +21,6 @@ import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.autojs.autojs.app.GlobalAppContext
import org.autojs.autojs.core.pref.Pref.getInt
import org.autojs.autojs.core.pref.Pref.getLinkedList
import org.autojs.autojs.core.pref.Pref.getStringOrNull
@@ -30,7 +29,6 @@ import org.autojs.autojs.core.pref.Pref.putLinkedList
import org.autojs.autojs.core.pref.Pref.putString
import org.autojs.autojs.core.pref.Pref.remove
import org.autojs.autojs.extension.ViewExtensions.setForceShowIconCompat
import org.autojs.autojs.external.fileprovider.AppFileProvider
import org.autojs.autojs.groundwork.WrapContentGridLayoutManger
import org.autojs.autojs.model.explorer.Explorer
import org.autojs.autojs.model.explorer.ExplorerChangeEvent
@@ -65,7 +63,6 @@ import org.autojs.autojs.ui.widget.FirstCharView
import org.autojs.autojs.util.ColorUtils
import org.autojs.autojs.util.EnvironmentUtils.externalStoragePath
import org.autojs.autojs.util.FileUtils
import org.autojs.autojs.util.IntentUtils
import org.autojs.autojs.util.Observers
import org.autojs.autojs.util.ViewUtils.showSnack
import org.autojs.autojs.util.WorkingDirectoryUtils
@@ -669,8 +666,6 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
internal inner class ExplorerItemViewHolder(itemView: View) : BindableViewHolder<Any>(itemView) {
private val globalAppContext by lazy { GlobalAppContext.get() }
private val mFirstChar: FirstCharView
private val mName: TextView
@@ -841,7 +836,7 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
notifyItemOperated()
}
mExplorerItem.isMediaPlayable -> {
mExplorerItem.play(context)
mExplorerItem.play(this@ExplorerView)
notifyItemOperated()
}
}
@@ -854,7 +849,7 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
notifyItemOperated()
}
mExplorerItem.isExternalEditable -> {
IntentUtils.editFile(globalAppContext, mExplorerItem.path, AppFileProvider.AUTHORITY)
mExplorerItem.edit(this@ExplorerView)
notifyItemOperated()
}
}
@@ -876,11 +871,11 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
private fun install() {
when {
mExplorerItem.isInstallable -> {
mExplorerItem.install(context)
mExplorerItem.install(this@ExplorerView)
notifyItemOperated()
}
else -> {
IntentUtils.viewFile(globalAppContext, mExplorerItem.path)
mExplorerItem.view(this@ExplorerView)
notifyItemOperated()
}
}

View File

@@ -20,9 +20,11 @@ import net.dongliu.apk.parser.ApkFile
import org.autojs.autojs.extension.MaterialDialogExtensions.makeSettingsLaunchable
import org.autojs.autojs.extension.MaterialDialogExtensions.makeTextCopyable
import org.autojs.autojs.extension.MaterialDialogExtensions.setCopyableTextIfAbsent
import org.autojs.autojs.external.fileprovider.AppFileProvider
import org.autojs.autojs.pio.PFiles
import org.autojs.autojs.runtime.api.AppUtils
import org.autojs.autojs.util.IntentUtils
import org.autojs.autojs.util.IntentUtils.ToastExceptionHolder
import org.autojs.autojs6.R
import org.autojs.autojs6.databinding.ApkFileInfoDialogListItemBinding
import java.io.File
@@ -49,7 +51,12 @@ object ApkInfoDialogManager {
.positiveColorRes(R.color.dialog_button_attraction)
.onPositive { materialDialog, _ ->
materialDialog.dismiss()
IntentUtils.installApk(context, apkFilePath)
IntentUtils.installApk(
context = context,
path = apkFilePath,
fileProviderAuthority = AppFileProvider.AUTHORITY,
exceptionHolder = ToastExceptionHolder(context),
)
}
.negativeText(R.string.text_cancel)
.negativeColorRes(R.color.dialog_button_default)

View File

@@ -14,6 +14,7 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.tabs.TabLayout
import io.reactivex.android.schedulers.AndroidSchedulers
import org.autojs.autojs.app.GlobalAppContext
import org.autojs.autojs.external.fileprovider.AppFileProvider
import org.autojs.autojs.model.explorer.ExplorerItem
import org.autojs.autojs.model.script.Scripts
import org.autojs.autojs.tool.SimpleObserver
@@ -29,6 +30,8 @@ import org.autojs.autojs.ui.main.ViewStatesManageable
import org.autojs.autojs.ui.project.ProjectConfigActivity
import org.autojs.autojs.ui.widget.ScrollAwareFABBehavior
import org.autojs.autojs.util.IntentUtils
import org.autojs.autojs.util.IntentUtils.SnackExceptionHolder
import org.autojs.autojs.util.IntentUtils.ToastExceptionHolder
import org.autojs.autojs.util.ViewUtils
import org.autojs.autojs6.R
import org.autojs.autojs6.databinding.FragmentExplorerBinding
@@ -103,7 +106,17 @@ class ExplorerFragment : ViewPagerFragment(0), OnFloatingActionButtonClickListen
}
}
private fun viewFile(item: ExplorerItem) = IntentUtils.viewFile(GlobalAppContext.get(), item.path)
private fun viewFile(item: ExplorerItem): Boolean {
val context = context ?: GlobalAppContext.get()
val exceptionHolder = view?.let { SnackExceptionHolder(it) } ?: ToastExceptionHolder(context)
return IntentUtils.viewFile(
context = context,
path = item.path,
mimeType = null,
fileProviderAuthority = AppFileProvider.AUTHORITY,
exceptionHolder = exceptionHolder,
)
}
override fun onFabClick(fab: FloatingActionButton) {
// initFloatingActionMenuIfNeeded(fab).run { if (isExpanded) collapse() else expand() }

View File

@@ -36,6 +36,7 @@ import org.autojs.autojs.apkbuilder.ApkBuilder;
import org.autojs.autojs.apkbuilder.keystore.KeyStore;
import org.autojs.autojs.core.pref.Language;
import org.autojs.autojs.extension.MaterialDialogExtensions;
import org.autojs.autojs.external.fileprovider.AppFileProvider;
import org.autojs.autojs.model.explorer.Explorers;
import org.autojs.autojs.model.script.ScriptFile;
import org.autojs.autojs.project.ProjectConfig;
@@ -56,6 +57,7 @@ import org.autojs.autojs.util.AndroidUtils.Abi;
import org.autojs.autojs.util.BitmapUtils;
import org.autojs.autojs.util.EnvironmentUtils;
import org.autojs.autojs.util.IntentUtils;
import org.autojs.autojs.util.IntentUtils.ToastExceptionHolder;
import org.autojs.autojs.util.ViewUtils;
import org.autojs.autojs.util.WorkingDirectoryUtils;
import org.autojs.autojs6.R;
@@ -987,7 +989,12 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
.content(getString(R.string.format_build_succeeded, outApk.getPath()))
.positiveText(R.string.text_install)
.positiveColorRes(R.color.dialog_button_attraction)
.onPositive((dialog, which) -> IntentUtils.installApk(BuildActivity.this, outApk.getPath()))
.onPositive((dialog, which) -> IntentUtils.installApk(
BuildActivity.this,
outApk.getPath(),
AppFileProvider.AUTHORITY,
new ToastExceptionHolder(BuildActivity.this)
))
.negativeText(R.string.text_cancel)
.negativeColorRes(R.color.dialog_button_default)
.neutralText(R.string.dialog_button_file_information)

View File

@@ -5,7 +5,10 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import android.view.View
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import com.google.android.material.snackbar.Snackbar
import org.autojs.autojs.external.fileprovider.AppFileProvider
import org.autojs.autojs.runtime.api.Mime
import org.autojs.autojs6.R
@@ -17,7 +20,7 @@ object IntentUtils {
true.also {
@Suppress("SpellCheckingInspection")
val url = "mqqwpa://im/chat?chat_type=wpa&uin=$qq"
Intent(Intent.ACTION_VIEW, Uri.parse(url))
Intent(Intent.ACTION_VIEW, url.toUri())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.let { context.startActivity(it) }
}
@@ -29,7 +32,7 @@ object IntentUtils {
true.also {
@Suppress("SpellCheckingInspection")
val url = "mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D$key"
Intent(Intent.ACTION_VIEW, Uri.parse(url))
Intent(Intent.ACTION_VIEW, url.toUri())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.let { context.startActivity(it) }
}
@@ -40,7 +43,7 @@ object IntentUtils {
@JvmOverloads
fun sendMailTo(context: Context, sendTo: String, title: String? = null, content: String? = null) = try {
true.also {
Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:$sendTo")).apply {
Intent(Intent.ACTION_SENDTO, "mailto:$sendTo".toUri()).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(Intent.EXTRA_CC, /* email */ arrayOf(sendTo))
title?.let { putExtra(Intent.EXTRA_SUBJECT, it) }
@@ -52,17 +55,18 @@ object IntentUtils {
}
@JvmStatic
fun browse(context: Context, link: String?) = try {
@JvmOverloads
fun browse(context: Context, link: String, exceptionHolder: ExceptionHolder? = null) = try {
true.also {
Intent(Intent.ACTION_VIEW, Uri.parse(link))
Intent(Intent.ACTION_VIEW, link.toUri())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.let { context.startActivity(it) }
}
} catch (ignored: ActivityNotFoundException) {
false.also {
ViewUtils.showToast(context, R.string.text_no_browser, true)
}
} catch (e: ActivityNotFoundException) {
exceptionHolder?.show(R.string.error_no_applications_available_for_browsing_this_link)
// ViewUtils.showToast(context, R.string.text_no_browser, true)
false.also { e.printStackTrace() }
}
fun shareText(context: Context, text: String?) = try {
@@ -73,9 +77,7 @@ object IntentUtils {
.let { context.startActivity(it) }
}
} catch (e: ActivityNotFoundException) {
false.also {
e.printStackTrace()
}
false.also { e.printStackTrace() }
}
@JvmOverloads
@@ -84,16 +86,21 @@ object IntentUtils {
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
addCategory(Intent.CATEGORY_DEFAULT)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
data = Uri.parse("package:$packageName")
data = "package:$packageName".toUri()
}.let { context.startActivity(it) }
}
} catch (ignored: ActivityNotFoundException) {
} catch (_: ActivityNotFoundException) {
false
}
@JvmStatic
@JvmOverloads
fun installApk(context: Context, path: String, fileProviderAuthority: String? = AppFileProvider.AUTHORITY) = try {
fun installApk(
context: Context,
path: String,
fileProviderAuthority: String = AppFileProvider.AUTHORITY,
exceptionHolder: ExceptionHolder? = null,
) = try {
Intent(Intent.ACTION_VIEW)
.setDataAndType(
getUriOfFile(context, path, fileProviderAuthority),
@@ -105,8 +112,9 @@ object IntentUtils {
.let { context.startActivity(it) }
true
} catch (e: ActivityNotFoundException) {
exceptionHolder?.show(R.string.error_no_applications_available_for_installing_this_file)
// ViewUtils.showToast(context, R.string.text_activity_not_found_for_apk_installing)
e.printStackTrace()
ViewUtils.showToast(context, R.string.text_activity_not_found_for_apk_installing)
false
}
@@ -116,51 +124,70 @@ object IntentUtils {
fun getUriOfFile(context: Context, path: String?, fileProviderAuthority: String? = AppFileProvider.AUTHORITY): Uri {
return fileProviderAuthority?.let {
FileProvider.getUriForFile(context, it, File(path ?: ""))
} ?: Uri.parse("file://$path")
} ?: "file://$path".toUri()
}
@JvmStatic
fun viewFile(context: Context, path: String, fileProviderAuthority: String? = AppFileProvider.AUTHORITY): Boolean {
fun viewFile(context: Context, path: String, fileProviderAuthority: String = AppFileProvider.AUTHORITY): Boolean {
return viewFile(context, path, Mime.fromFileOr(path, Mime.WILDCARD), fileProviderAuthority)
}
@JvmStatic
@JvmOverloads
fun viewFile(context: Context, uri: Uri, mimeType: String?, fileProviderAuthority: String? = AppFileProvider.AUTHORITY): Boolean {
if (uri.scheme == "file") {
return uri.path?.let { viewFile(context, it, mimeType, fileProviderAuthority) } ?: false
}
return try {
true.also {
Intent(Intent.ACTION_VIEW)
.setDataAndType(uri, mimeType)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
.let { context.startActivity(it) }
}
} catch (e: Exception) {
false.also { e.printStackTrace() }
fun viewFile(
context: Context,
uri: Uri,
mimeType: String? = null,
fileProviderAuthority: String = AppFileProvider.AUTHORITY,
exceptionHolder: ExceptionHolder? = null,
): Boolean = when (uri.scheme) {
uri.scheme -> {
uri.path?.let { viewFile(context, it, mimeType, fileProviderAuthority) } ?: false
}
else -> launchViewIntent(context, uri, mimeType, exceptionHolder)
}
@JvmStatic
fun viewFile(context: Context, path: String, mimeType: String?, fileProviderAuthority: String? = AppFileProvider.AUTHORITY) = try {
fun viewFile(
context: Context,
path: String,
mimeType: String? = null,
fileProviderAuthority: String = AppFileProvider.AUTHORITY,
exceptionHolder: ExceptionHolder? = null,
) = launchViewIntent(
context = context,
uri = getUriOfFile(context, path, fileProviderAuthority),
mimeType = mimeType ?: Mime.fromFileOrWildcard(path),
exceptionHolder = exceptionHolder,
)
private fun launchViewIntent(
context: Context,
uri: Uri,
mimeType: String?,
exceptionHolder: ExceptionHolder? = null,
) = try {
true.also {
Intent(Intent.ACTION_VIEW)
.setDataAndType(getUriOfFile(context, path, fileProviderAuthority), mimeType)
.setDataAndType(uri, mimeType)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
.let { context.startActivity(it) }
}
} catch (e: ActivityNotFoundException) {
} catch (e: Exception) {
exceptionHolder?.show(R.string.error_no_applications_available_for_viewing_this_file)
false.also { e.printStackTrace() }
}
@JvmStatic
@JvmOverloads
fun editFile(context: Context, path: String, fileProviderAuthority: String? = AppFileProvider.AUTHORITY) = try {
fun editFile(
context: Context,
path: String,
fileProviderAuthority: String = AppFileProvider.AUTHORITY,
exceptionHolder: ExceptionHolder? = null,
) = try {
true.also {
Intent(Intent.ACTION_EDIT)
.setDataAndType(
@@ -173,6 +200,28 @@ object IntentUtils {
.let { context.startActivity(it) }
}
} catch (e: ActivityNotFoundException) {
exceptionHolder?.show(R.string.error_no_applications_available_for_editing_this_file)
false.also { e.printStackTrace() }
}
@JvmStatic
@JvmOverloads
fun sendFile(
context: Context,
path: String,
fileProviderAuthority: String = AppFileProvider.AUTHORITY,
exceptionHolder: ExceptionHolder? = null,
) = try {
true.also {
Intent(Intent.ACTION_SEND)
.setType("text/plain")
.putExtra(Intent.EXTRA_STREAM, getUriOfFile(context, path, fileProviderAuthority))
.let { Intent.createChooser(it, context.getString(R.string.text_send)) }
.apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
.let { context.startActivity(it) }
}
} catch (e: ActivityNotFoundException) {
exceptionHolder?.show(R.string.error_no_applications_available_for_sending_this_file)
false.also { e.printStackTrace() }
}
@@ -184,4 +233,61 @@ object IntentUtils {
e.printStackTrace()
}
data class SnackExceptionHolder @JvmOverloads constructor(
private val view: View,
private val overriddenMessage: String? = null,
private val duration: Int = Snackbar.LENGTH_LONG,
) : ExceptionHolder {
@JvmOverloads
constructor(
view: View,
overriddenMessageRes: Int,
duration: Int = Snackbar.LENGTH_LONG,
) : this(
view = view,
overriddenMessage = view.context.getString(overriddenMessageRes),
duration = duration,
)
override fun show(message: String?) {
ViewUtils.showSnack(view, overriddenMessage ?: message ?: "Failed to start an activity", duration)
}
override fun show(messageRes: Int) {
show(view.context.getString(messageRes))
}
}
data class ToastExceptionHolder @JvmOverloads constructor(
private val context: Context,
private val overriddenMessage: String? = null,
private val isLong: Boolean = true,
) : ExceptionHolder {
@JvmOverloads
constructor(
context: Context,
overriddenMessageRes: Int,
isLong: Boolean = true,
) : this(
context = context,
overriddenMessage = context.getString(overriddenMessageRes),
isLong = isLong,
)
override fun show(message: String?) {
ViewUtils.showToast(context, overriddenMessage ?: message ?: "Failed to start an activity", isLong)
}
override fun show(messageRes: Int) {
show(context.getString(messageRes))
}
}
interface ExceptionHolder {
fun show(message: String? = null)
fun show(messageRes: Int)
}
}

View File

@@ -1042,5 +1042,11 @@
<string name="text_write_system_settings">كتابة إعدادات النظام</string>
<string name="text_hide_node">إخفاء هذه العقدة</string>
<string name="text_hide_same_frame_nodes">إخفاء العقدة ذات الإطار المماثل</string>
<string name="error_no_applications_available_for_editing_this_file">لا توجد تطبيقات متاحة لتحرير هذا الملف</string>
<string name="error_no_applications_available_for_browsing_this_link">لا توجد تطبيقات متاحة لاستعراض هذا الرابط</string>
<string name="error_no_applications_available_for_installing_this_file">لا توجد تطبيقات متاحة لتثبيت هذا الملف</string>
<string name="error_no_applications_available_for_viewing_this_file">لا توجد تطبيقات متاحة لعرض هذا الملف</string>
<string name="error_no_applications_available_for_sending_this_file">لا توجد تطبيقات متاحة لإرسال هذا الملف</string>
<string name="error_no_applications_available_for_playing_this_file">لا توجد تطبيقات متاحة لتشغيل هذا الملف</string>
</resources>

View File

@@ -1037,5 +1037,11 @@
<string name="text_write_system_settings">Write system settings</string>
<string name="text_hide_node">Hide this node</string>
<string name="text_hide_same_frame_nodes">Hide same frame nodes</string>
<string name="error_no_applications_available_for_editing_this_file">No applications available for editing this file</string>
<string name="error_no_applications_available_for_browsing_this_link">No applications available for browsing this link</string>
<string name="error_no_applications_available_for_installing_this_file">No applications available for installing this file</string>
<string name="error_no_applications_available_for_viewing_this_file">No applications available for viewing this file</string>
<string name="error_no_applications_available_for_sending_this_file">No applications available for sending this file</string>
<string name="error_no_applications_available_for_playing_this_file">No applications available for playing this file</string>
</resources>

View File

@@ -1040,5 +1040,11 @@
<string name="text_write_system_settings">Escribir la configuración del sistema</string>
<string name="text_hide_node">Ocultar este nodo</string>
<string name="text_hide_same_frame_nodes">Ocultar nodo del mismo marco</string>
<string name="error_no_applications_available_for_editing_this_file">No hay aplicaciones disponibles para editar este archivo</string>
<string name="error_no_applications_available_for_browsing_this_link">No hay aplicaciones disponibles para abrir este enlace</string>
<string name="error_no_applications_available_for_installing_this_file">No hay aplicaciones disponibles para instalar este archivo</string>
<string name="error_no_applications_available_for_viewing_this_file">No hay aplicaciones disponibles para ver este archivo</string>
<string name="error_no_applications_available_for_sending_this_file">No hay aplicaciones disponibles para enviar este archivo</string>
<string name="error_no_applications_available_for_playing_this_file">No hay aplicaciones disponibles para reproducir este archivo</string>
</resources>

View File

@@ -1040,5 +1040,11 @@
<string name="text_write_system_settings">Écrire les paramètres système</string>
<string name="text_hide_node">Masquer ce nœud</string>
<string name="text_hide_same_frame_nodes">Masquer le nœud du même cadre</string>
<string name="error_no_applications_available_for_editing_this_file">Aucune application disponible pour modifier ce fichier</string>
<string name="error_no_applications_available_for_browsing_this_link">Aucune application disponible pour parcourir ce lien</string>
<string name="error_no_applications_available_for_installing_this_file">Aucune application disponible pour installer ce fichier</string>
<string name="error_no_applications_available_for_viewing_this_file">Aucune application disponible pour afficher ce fichier</string>
<string name="error_no_applications_available_for_sending_this_file">Aucune application disponible pour envoyer ce fichier</string>
<string name="error_no_applications_available_for_playing_this_file">Aucune application disponible pour lire ce fichier</string>
</resources>

View File

@@ -1041,5 +1041,11 @@
<string name="text_write_system_settings">システム設定の書き込み</string>
<string name="text_hide_node">このノードを隠す</string>
<string name="text_hide_same_frame_nodes">同じフレームのノードを隠す</string>
<string name="error_no_applications_available_for_editing_this_file">このファイルを編集できるアプリがありません</string>
<string name="error_no_applications_available_for_browsing_this_link">このリンクを閲覧できるアプリがありません</string>
<string name="error_no_applications_available_for_installing_this_file">このファイルをインストールできるアプリがありません</string>
<string name="error_no_applications_available_for_viewing_this_file">このファイルを表示できるアプリがありません</string>
<string name="error_no_applications_available_for_sending_this_file">このファイルを送信できるアプリがありません</string>
<string name="error_no_applications_available_for_playing_this_file">このファイルを再生できるアプリがありません</string>
</resources>

View File

@@ -1042,5 +1042,11 @@
<string name="text_write_system_settings">시스템 설정을 작성하십시오</string>
<string name="text_hide_node">이 노드를 숨기기</string>
<string name="text_hide_same_frame_nodes">동일 프레임의 노드를 숨기기</string>
<string name="error_no_applications_available_for_editing_this_file">이 파일을 편집할 수 있는 앱이 없습니다</string>
<string name="error_no_applications_available_for_browsing_this_link">이 링크를 탐색할 수 있는 앱이 없습니다</string>
<string name="error_no_applications_available_for_installing_this_file">이 파일을 설치할 수 있는 앱이 없습니다</string>
<string name="error_no_applications_available_for_viewing_this_file">이 파일을 볼 수 있는 앱이 없습니다</string>
<string name="error_no_applications_available_for_sending_this_file">이 파일을 전송할 수 있는 앱이 없습니다</string>
<string name="error_no_applications_available_for_playing_this_file">이 파일을 재생할 수 있는 앱이 없습니다</string>
</resources>

View File

@@ -1040,5 +1040,11 @@
<string name="text_write_system_settings">Запись системных настроек</string>
<string name="text_hide_node">Скрыть этот узел</string>
<string name="text_hide_same_frame_nodes">Скрыть узел того же фрейма</string>
<string name="error_no_applications_available_for_editing_this_file">Нет приложений для редактирования этого файла</string>
<string name="error_no_applications_available_for_browsing_this_link">Нет приложений для просмотра этой ссылки</string>
<string name="error_no_applications_available_for_installing_this_file">Нет приложений для установки этого файла</string>
<string name="error_no_applications_available_for_viewing_this_file">Нет приложений для просмотра этого файла</string>
<string name="error_no_applications_available_for_sending_this_file">Нет приложений для отправки этого файла</string>
<string name="error_no_applications_available_for_playing_this_file">Нет приложений для воспроизведения этого файла</string>
</resources>

View File

@@ -1038,5 +1038,11 @@
<string name="text_write_system_settings">修改系統設置</string>
<string name="text_hide_node">隱藏此節點</string>
<string name="text_hide_same_frame_nodes">隱藏同框節點</string>
<string name="error_no_applications_available_for_editing_this_file">未找到用於編輯該文件的應用</string>
<string name="error_no_applications_available_for_browsing_this_link">未找到用於瀏覽該鏈接的應用</string>
<string name="error_no_applications_available_for_installing_this_file">未找到用於安裝該文件的應用</string>
<string name="error_no_applications_available_for_viewing_this_file">未找到用於查看該文件的應用</string>
<string name="error_no_applications_available_for_sending_this_file">未找到用於發送該文件的應用</string>
<string name="error_no_applications_available_for_playing_this_file">未找到用於播放該文件的應用</string>
</resources>

View File

@@ -1038,5 +1038,11 @@
<string name="text_write_system_settings">修改系統設定</string>
<string name="text_hide_node">隱藏此節點</string>
<string name="text_hide_same_frame_nodes">隱藏同框節點</string>
<string name="error_no_applications_available_for_editing_this_file">未找到用於編輯該檔案的應用</string>
<string name="error_no_applications_available_for_browsing_this_link">未找到用於瀏覽該連結的應用</string>
<string name="error_no_applications_available_for_installing_this_file">未找到用於安裝該檔案的應用</string>
<string name="error_no_applications_available_for_viewing_this_file">未找到用於檢視該檔案的應用</string>
<string name="error_no_applications_available_for_sending_this_file">未找到用於傳送該檔案的應用</string>
<string name="error_no_applications_available_for_playing_this_file">未找到用於播放該檔案的應用</string>
</resources>

View File

@@ -1038,5 +1038,11 @@
<string name="text_write_system_settings">修改系统设置</string>
<string name="text_hide_node">隐藏此节点</string>
<string name="text_hide_same_frame_nodes">隐藏同框节点</string>
<string name="error_no_applications_available_for_editing_this_file">未找到用于编辑该文件的应用</string>
<string name="error_no_applications_available_for_browsing_this_link">未找到用于浏览该链接的应用</string>
<string name="error_no_applications_available_for_installing_this_file">未找到用于安装该文件的应用</string>
<string name="error_no_applications_available_for_viewing_this_file">未找到用于查看该文件的应用</string>
<string name="error_no_applications_available_for_sending_this_file">未找到用于发送该文件的应用</string>
<string name="error_no_applications_available_for_playing_this_file">未找到用于播放该文件的应用</string>
</resources>

View File

@@ -1268,5 +1268,11 @@
<string name="text_write_system_settings">Write system settings</string>
<string name="text_hide_node">Hide this node</string>
<string name="text_hide_same_frame_nodes">Hide same frame nodes</string>
<string name="error_no_applications_available_for_editing_this_file">No applications available for editing this file</string>
<string name="error_no_applications_available_for_browsing_this_link">No applications available for browsing this link</string>
<string name="error_no_applications_available_for_installing_this_file">No applications available for installing this file</string>
<string name="error_no_applications_available_for_viewing_this_file">No applications available for viewing this file</string>
<string name="error_no_applications_available_for_sending_this_file">No applications available for sending this file</string>
<string name="error_no_applications_available_for_playing_this_file">No applications available for playing this file</string>
</resources>