diff --git a/app/src/main/java/io/neoterm/App.kt b/app/src/main/java/io/neoterm/App.kt index d6620cc..0db4a5b 100644 --- a/app/src/main/java/io/neoterm/App.kt +++ b/app/src/main/java/io/neoterm/App.kt @@ -1,13 +1,13 @@ package io.neoterm import android.annotation.SuppressLint -import androidx.appcompat.app.AlertDialog import android.app.Application import android.content.Context import android.content.Intent import android.net.Uri import android.view.Gravity import android.widget.Toast +import androidx.appcompat.app.AlertDialog import io.neoterm.component.NeoInitializer import io.neoterm.frontend.config.NeoPreference import io.neoterm.ui.bonus.BonusActivity @@ -31,16 +31,16 @@ class App : Application() { fun errorDialog(context: Context, message: String, dismissCallback: (() -> Unit)?) { AlertDialog.Builder(context) - .setTitle(R.string.error) - .setMessage(message) - .setNegativeButton(android.R.string.no, null) - .setPositiveButton(R.string.show_help, { _, _ -> - openHelpLink() - }) - .setOnDismissListener { - dismissCallback?.invoke() - } - .show() + .setTitle(R.string.error) + .setMessage(message) + .setNegativeButton(android.R.string.no, null) + .setPositiveButton(R.string.show_help) { _, _ -> + openHelpLink() + } + .setOnDismissListener { + dismissCallback?.invoke() + } + .show() } fun openHelpLink() { @@ -72,6 +72,5 @@ class App : Application() { fun get(): App { return app!! } - } } \ No newline at end of file diff --git a/app/src/main/java/io/neoterm/component/colorscheme/ColorSchemeComponent.kt b/app/src/main/java/io/neoterm/component/colorscheme/ColorSchemeComponent.kt index 0325643..daf0a39 100644 --- a/app/src/main/java/io/neoterm/component/colorscheme/ColorSchemeComponent.kt +++ b/app/src/main/java/io/neoterm/component/colorscheme/ColorSchemeComponent.kt @@ -13,8 +13,8 @@ import io.neoterm.frontend.logging.NLog import io.neoterm.frontend.terminal.TerminalView import io.neoterm.frontend.terminal.extrakey.ExtraKeysView import io.neoterm.utils.AssetsUtils -import io.neoterm.utils.FileUtils import java.io.File +import java.nio.file.Files /** * @author kiva @@ -121,7 +121,9 @@ class ColorSchemeComponent : ConfigFileBasedComponent(NeoTermPat val component = ComponentManager.getComponent() val content = component.newGenerator(colorScheme).generateCode(colorScheme) - if (!FileUtils.writeFile(colorFile, content.toByteArray())) { + kotlin.runCatching { + Files.write(colorFile.toPath(), content.toByteArray()) + }.onFailure { throw RuntimeException("Failed to save file ${colorFile.absolutePath}") } } diff --git a/app/src/main/java/io/neoterm/component/pm/SourceHelper.kt b/app/src/main/java/io/neoterm/component/pm/SourceHelper.kt index c9069cb..1c9163a 100644 --- a/app/src/main/java/io/neoterm/component/pm/SourceHelper.kt +++ b/app/src/main/java/io/neoterm/component/pm/SourceHelper.kt @@ -3,9 +3,10 @@ package io.neoterm.component.pm import io.neoterm.frontend.component.ComponentManager import io.neoterm.frontend.config.NeoTermPath import io.neoterm.frontend.logging.NLog -import io.neoterm.utils.FileUtils import java.io.File import java.net.URL +import java.nio.file.Files +import java.nio.file.Paths /** * @author kiva @@ -17,13 +18,14 @@ object SourceHelper { } fun syncSource(sourceManager: SourceManager) { - val sourceFile = File(NeoTermPath.SOURCE_FILE) val content = buildString { this.append("# Generated by NeoTerm-Preference\n") sourceManager.getEnabledSources() .joinTo(this, "\n") { "deb [trusted=yes] ${it.url} ${it.repo}\n" } } - FileUtils.writeFile(sourceFile, content.toByteArray()) + kotlin.runCatching { + Files.write(Paths.get(NeoTermPath.SOURCE_FILE), content.toByteArray()) + } } fun detectSourceFiles(): List { @@ -36,10 +38,10 @@ object SourceHelper { File(NeoTermPath.PACKAGE_LIST_DIR) .listFiles() - .filterTo(sourceFiles, { file -> + .filterTo(sourceFiles) { file -> prefixes.filter { file.name.startsWith(it) } - .count() > 0 - }) + .count() > 0 + } } catch (e: Exception) { sourceFiles.clear() NLog.e("PM", "Failed to detect source files: ${e.localizedMessage}") @@ -59,8 +61,7 @@ object SourceHelper { val path = url.path if (path != null && path.isNotEmpty()) { builder.append("_") - val fixedPath = path.replace("/", "_") - .substring(1) // skip the last '/' + val fixedPath = path.replace("/", "_").substring(1) // skip the last '/' builder.append(fixedPath) } builder.append("_dists_${source.repo.replace(" ".toRegex(), "_")}_binary-") diff --git a/app/src/main/java/io/neoterm/frontend/config/NeoConfigureFile.kt b/app/src/main/java/io/neoterm/frontend/config/NeoConfigureFile.kt index ee0506c..a9b32f7 100644 --- a/app/src/main/java/io/neoterm/frontend/config/NeoConfigureFile.kt +++ b/app/src/main/java/io/neoterm/frontend/config/NeoConfigureFile.kt @@ -2,9 +2,8 @@ package io.neoterm.frontend.config import io.neolang.parser.NeoLangParser import io.neolang.visitor.ConfigVisitor -import io.neoterm.frontend.logging.NLog -import io.neoterm.utils.FileUtils import java.io.File +import java.nio.file.Files /** * @author kiva @@ -13,30 +12,15 @@ open class NeoConfigureFile(val configureFile: File) { private val configParser = NeoLangParser() open protected var configVisitor : ConfigVisitor? = null - fun getVisitor(): ConfigVisitor { - checkParsed() - return configVisitor!! - } + fun getVisitor() = configVisitor ?: throw IllegalStateException("Configure file not loaded or parse failed.") - open fun parseConfigure(): Boolean { - val configContent = FileUtils.readFile(configureFile) - if (configContent == null) { - NLog.e("ConfigureFile", "Cannot read file $configureFile") - return false - } - val programCode = String(configContent) + open fun parseConfigure() = kotlin.runCatching { + val programCode = String(Files.readAllBytes(configureFile.toPath())) configParser.setInputSource(programCode) val ast = configParser.parse() val astVisitor = ast.visit().getVisitor(ConfigVisitor::class.java) ?: return false astVisitor.start() configVisitor = astVisitor.getCallback() - return true - } - - private fun checkParsed() { - if (configVisitor == null) { - throw IllegalStateException("Configure file not loaded or parse failed.") - } - } + }.isSuccess } diff --git a/app/src/main/java/io/neoterm/frontend/config/NeoPreference.kt b/app/src/main/java/io/neoterm/frontend/config/NeoPreference.kt index 5aa2428..da2e104 100644 --- a/app/src/main/java/io/neoterm/frontend/config/NeoPreference.kt +++ b/app/src/main/java/io/neoterm/frontend/config/NeoPreference.kt @@ -11,8 +11,8 @@ import io.neoterm.R import io.neoterm.backend.TerminalSession import io.neoterm.frontend.logging.NLog import io.neoterm.services.NeoTermService -import io.neoterm.utils.FileUtils import java.io.File +import java.nio.file.Files /** @@ -46,12 +46,13 @@ object NeoPreference { // load apt source val sourceFile = File(NeoTermPath.SOURCE_FILE) - val bytes = FileUtils.readFile(sourceFile) - if (bytes != null) { - val source = String(FileUtils.readFile(sourceFile)!!).trim().trimEnd() - val array = source.split(" ") - if (array.size >= 2 && array[0] == "deb") { - store(R.string.key_package_source, array[1]) + kotlin.runCatching { + Files.readAllBytes(sourceFile.toPath())?.let { + val source = String(it).trim().trimEnd() + val array = source.split(" ") + if (array.size >= 2 && array[0] == "deb") { + store(R.string.key_package_source, array[1]) + } } } } @@ -94,16 +95,16 @@ object NeoPreference { fun storeCurrentSession(session: TerminalSession) { preference!!.edit() - .putString(KEY_CURRENT_SESSION, session.mHandle) - .apply() + .putString(KEY_CURRENT_SESSION, session.mHandle) + .apply() } fun getCurrentSession(termService: NeoTermService?): TerminalSession? { val sessionHandle = PreferenceManager.getDefaultSharedPreferences(termService!!) - .getString(KEY_CURRENT_SESSION, "") + .getString(KEY_CURRENT_SESSION, "") return termService.sessions - .singleOrNull { it.mHandle == sessionHandle } + .singleOrNull { it.mHandle == sessionHandle } } fun setLoginShellName(loginProgramName: String?): Boolean { @@ -164,73 +165,101 @@ object NeoPreference { } fun getFontSize(): Int { - return loadInt(KEY_FONT_SIZE, - DefaultValues.fontSize) + return loadInt( + KEY_FONT_SIZE, + DefaultValues.fontSize + ) } fun getInitialCommand(): String { - return loadString(R.string.key_general_initial_command, - DefaultValues.initialCommand) + return loadString( + R.string.key_general_initial_command, + DefaultValues.initialCommand + ) } fun isBellEnabled(): Boolean { - return loadBoolean(R.string.key_general_bell, - DefaultValues.enableBell) + return loadBoolean( + R.string.key_general_bell, + DefaultValues.enableBell + ) } fun isVibrateEnabled(): Boolean { - return loadBoolean(R.string.key_general_vibrate, - DefaultValues.enableVibrate) + return loadBoolean( + R.string.key_general_vibrate, + DefaultValues.enableVibrate + ) } - fun isExecveWrapperEnabled() : Boolean { - return loadBoolean(R.string.key_general_use_execve_wrapper, - DefaultValues.enableExecveWrapper) + fun isExecveWrapperEnabled(): Boolean { + return loadBoolean( + R.string.key_general_use_execve_wrapper, + DefaultValues.enableExecveWrapper + ) } - fun isSpecialVolumeKeysEnabled() : Boolean { - return loadBoolean(R.string.key_general_volume_as_control, - DefaultValues.enableSpecialVolumeKeys) + fun isSpecialVolumeKeysEnabled(): Boolean { + return loadBoolean( + R.string.key_general_volume_as_control, + DefaultValues.enableSpecialVolumeKeys + ) } - fun isAutoCompletionEnabled() : Boolean { - return loadBoolean(R.string.key_general_auto_completion, - DefaultValues.enableAutoCompletion) + fun isAutoCompletionEnabled(): Boolean { + return loadBoolean( + R.string.key_general_auto_completion, + DefaultValues.enableAutoCompletion + ) } fun isBackButtonBeMappedToEscapeEnabled(): Boolean { - return loadBoolean(R.string.key_generaL_backspace_map_to_esc, - DefaultValues.enableBackButtonBeMappedToEscape) + return loadBoolean( + R.string.key_generaL_backspace_map_to_esc, + DefaultValues.enableBackButtonBeMappedToEscape + ) } fun isExtraKeysEnabled(): Boolean { - return loadBoolean(R.string.key_ui_eks_enabled, - DefaultValues.enableExtraKeys) + return loadBoolean( + R.string.key_ui_eks_enabled, + DefaultValues.enableExtraKeys + ) } - fun isExplicitExtraKeysWeightEnabled() :Boolean { - return loadBoolean(R.string.key_ui_eks_weight_explicit, - DefaultValues.enableExplicitExtraKeysWeight) + fun isExplicitExtraKeysWeightEnabled(): Boolean { + return loadBoolean( + R.string.key_ui_eks_weight_explicit, + DefaultValues.enableExplicitExtraKeysWeight + ) } - fun isFullScreenEnabled() : Boolean { - return loadBoolean(R.string.key_ui_fullscreen, - DefaultValues.enableFullScreen) + fun isFullScreenEnabled(): Boolean { + return loadBoolean( + R.string.key_ui_fullscreen, + DefaultValues.enableFullScreen + ) } - fun isHideToolbarEnabled() :Boolean { - return loadBoolean(R.string.key_ui_hide_toolbar, - DefaultValues.enableAutoHideToolbar) + fun isHideToolbarEnabled(): Boolean { + return loadBoolean( + R.string.key_ui_hide_toolbar, + DefaultValues.enableAutoHideToolbar + ) } - fun isNextTabEnabled() :Boolean { - return loadBoolean(R.string.key_ui_next_tab_anim, - DefaultValues.enableSwitchNextTab) + fun isNextTabEnabled(): Boolean { + return loadBoolean( + R.string.key_ui_next_tab_anim, + DefaultValues.enableSwitchNextTab + ) } - fun isWordBasedImeEnabled() : Boolean { - return loadBoolean(R.string.key_general_enable_word_based_ime, - DefaultValues.enableWordBasedIme) + fun isWordBasedImeEnabled(): Boolean { + return loadBoolean( + R.string.key_general_enable_word_based_ime, + DefaultValues.enableWordBasedIme + ) } /** diff --git a/app/src/main/java/io/neoterm/setup/helper/URLAvailability.java b/app/src/main/java/io/neoterm/setup/helper/URLAvailability.java deleted file mode 100644 index 7bc8423..0000000 --- a/app/src/main/java/io/neoterm/setup/helper/URLAvailability.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.neoterm.setup.helper; - -import android.content.Context; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; - -import io.neoterm.utils.NetworkUtils; - -/** - * @author kiva - */ - -public final class URLAvailability { - public enum ResultCode { - URL_OK, - URL_CONNECTION_FAILED, - URL_INVALID, - URL_NO_INTERNET, - } - - public static ResultCode checkUrlAvailability(Context context, String urlString) { - if (!NetworkUtils.INSTANCE.isNetworkAvailable(context)) { - return ResultCode.URL_NO_INTERNET; - } - - try { - URL url = new URL(urlString); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.disconnect(); - - } catch (MalformedURLException e) { - return ResultCode.URL_INVALID; - - } catch (IOException | ClassCastException e) { - return ResultCode.URL_CONNECTION_FAILED; - } - - return ResultCode.URL_OK; - } -} diff --git a/app/src/main/java/io/neoterm/ui/customize/CustomizeActivity.kt b/app/src/main/java/io/neoterm/ui/customize/CustomizeActivity.kt index 76e91a7..161b74b 100644 --- a/app/src/main/java/io/neoterm/ui/customize/CustomizeActivity.kt +++ b/app/src/main/java/io/neoterm/ui/customize/CustomizeActivity.kt @@ -1,6 +1,5 @@ package io.neoterm.ui.customize -import androidx.appcompat.app.AppCompatActivity import android.content.Intent import android.os.Bundle import android.view.MenuItem @@ -14,10 +13,10 @@ import io.neoterm.component.colorscheme.ColorSchemeComponent import io.neoterm.component.font.FontComponent import io.neoterm.frontend.component.ComponentManager import io.neoterm.frontend.config.NeoTermPath -import io.neoterm.utils.FileUtils import io.neoterm.utils.MediaUtils import java.io.File -import java.io.FileInputStream +import java.nio.file.Files +import java.nio.file.Paths /** * @author kiva @@ -41,7 +40,10 @@ class CustomizeActivity : BaseCustomizeActivity() { val intent = Intent() intent.action = Intent.ACTION_GET_CONTENT intent.type = "*/*" - startActivityForResult(Intent.createChooser(intent, getString(R.string.install_color)), REQUEST_SELECT_COLOR) + startActivityForResult( + Intent.createChooser(intent, getString(R.string.install_color)), + REQUEST_SELECT_COLOR + ) } } @@ -50,40 +52,47 @@ class CustomizeActivity : BaseCustomizeActivity() { val colorSchemeComponent = ComponentManager.getComponent() setupSpinner(R.id.custom_font_spinner, fontComponent.getFontNames(), - fontComponent.getCurrentFontName(), object : AdapterView.OnItemSelectedListener { - override fun onNothingSelected(parent: AdapterView<*>?) { - } - - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - val fontName = parent!!.adapter!!.getItem(position) as String - val font = fontComponent.getFont(fontName) - fontComponent.applyFont(terminalView, extraKeysView, font) - fontComponent.setCurrentFont(fontName) - } - }) - - val colorData = listOf(getString(R.string.new_color_scheme), - *colorSchemeComponent.getColorSchemeNames().toTypedArray()) - setupSpinner(R.id.custom_color_spinner, colorData, - colorSchemeComponent.getCurrentColorSchemeName(), object : AdapterView.OnItemSelectedListener { - override fun onNothingSelected(parent: AdapterView<*>?) { - } - - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - if (position == 0) { - val intent = Intent(this@CustomizeActivity, ColorSchemeActivity::class.java) - startActivity(intent) - return + fontComponent.getCurrentFontName(), object : AdapterView.OnItemSelectedListener { + override fun onNothingSelected(parent: AdapterView<*>?) { } - val colorName = parent!!.adapter!!.getItem(position) as String - val color = colorSchemeComponent.getColorScheme(colorName) - colorSchemeComponent.applyColorScheme(terminalView, extraKeysView, color) - colorSchemeComponent.setCurrentColorScheme(colorName) - } - }) + + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + val fontName = parent!!.adapter!!.getItem(position) as String + val font = fontComponent.getFont(fontName) + fontComponent.applyFont(terminalView, extraKeysView, font) + fontComponent.setCurrentFont(fontName) + } + }) + + val colorData = listOf( + getString(R.string.new_color_scheme), + *colorSchemeComponent.getColorSchemeNames().toTypedArray() + ) + setupSpinner(R.id.custom_color_spinner, colorData, + colorSchemeComponent.getCurrentColorSchemeName(), object : AdapterView.OnItemSelectedListener { + override fun onNothingSelected(parent: AdapterView<*>?) { + } + + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + if (position == 0) { + val intent = Intent(this@CustomizeActivity, ColorSchemeActivity::class.java) + startActivity(intent) + return + } + val colorName = parent!!.adapter!!.getItem(position) as String + val color = colorSchemeComponent.getColorScheme(colorName) + colorSchemeComponent.applyColorScheme(terminalView, extraKeysView, color) + colorSchemeComponent.setCurrentColorScheme(colorName) + } + }) } - private fun setupSpinner(id: Int, data: List, selected: String, listener: AdapterView.OnItemSelectedListener) : Spinner { + private fun setupSpinner( + id: Int, + data: List, + selected: String, + listener: AdapterView.OnItemSelectedListener + ): Spinner { val spinner = findViewById(id) val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, data) adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) @@ -104,7 +113,7 @@ class CustomizeActivity : BaseCustomizeActivity() { } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (resultCode == AppCompatActivity.RESULT_OK && data != null) { + if (resultCode == RESULT_OK && data != null) { val selected = MediaUtils.getPath(this, data.data) if (selected != null && selected.isNotEmpty()) { when (requestCode) { @@ -127,15 +136,11 @@ class CustomizeActivity : BaseCustomizeActivity() { } private fun installFileTo(file: String, targetDir: String) { - try { - val fileObject = File(file) - val input = FileInputStream(fileObject.absolutePath) - val targetFile = File(targetDir, fileObject.name) - input.use { - FileUtils.writeFile(targetFile, it) - } - } catch (e: Exception) { - Toast.makeText(this, getString(R.string.error) + ": ${e.localizedMessage}", Toast.LENGTH_LONG).show() + kotlin.runCatching { + val source = File(file) + Files.copy(source.toPath(), Paths.get(targetDir, source.name)) + }.onFailure { + Toast.makeText(this, getString(R.string.error) + ": ${it.localizedMessage}", Toast.LENGTH_LONG).show() } } diff --git a/app/src/main/java/io/neoterm/ui/setup/SetupActivity.kt b/app/src/main/java/io/neoterm/ui/setup/SetupActivity.kt index 8245e08..7cdc314 100644 --- a/app/src/main/java/io/neoterm/ui/setup/SetupActivity.kt +++ b/app/src/main/java/io/neoterm/ui/setup/SetupActivity.kt @@ -1,14 +1,14 @@ package io.neoterm.ui.setup -import androidx.appcompat.app.AlertDialog import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity import android.view.LayoutInflater import android.view.View import android.widget.* +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import io.neoterm.App import io.neoterm.R import io.neoterm.component.pm.SourceHelper @@ -19,11 +19,9 @@ import io.neoterm.setup.SourceConnection import io.neoterm.setup.connections.BackupFileConnection import io.neoterm.setup.connections.LocalFileConnection import io.neoterm.setup.connections.NetworkConnection -import io.neoterm.setup.helper.URLAvailability import io.neoterm.utils.MediaUtils import io.neoterm.utils.PackageUtils import java.io.File -import java.lang.Exception /** @@ -39,9 +37,9 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener private var setupParameterUri: Uri? = null private val hintMapping = arrayOf( - R.id.setup_method_online, R.string.setup_hint_online, - R.id.setup_method_local, R.string.setup_hint_local, - R.id.setup_method_backup, R.string.setup_hint_backup + R.id.setup_method_online, R.string.setup_hint_online, + R.id.setup_method_local, R.string.setup_hint_local, + R.id.setup_method_backup, R.string.setup_hint_backup ) override fun onCreate(savedInstanceState: Bundle?) { @@ -103,7 +101,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener R.id.setup_method_backup, R.id.setup_method_local -> { SetupHelper.makeErrorDialog(this, R.string.setup_error_parameter_null) - .show() + .show() return } } @@ -137,8 +135,10 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener val intent = Intent(Intent.ACTION_GET_CONTENT) intent.type = "*/*" try { - startActivityForResult( Intent.createChooser(intent, getString(R.string.setup_local)), - REQUEST_SELECT_PARAMETER) + startActivityForResult( + Intent.createChooser(intent, getString(R.string.setup_local)), + REQUEST_SELECT_PARAMETER + ) } catch (ignore: ActivityNotFoundException) { Toast.makeText(this, R.string.no_file_picker, Toast.LENGTH_SHORT).show() } @@ -151,15 +151,15 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener val edit = view.findViewById(R.id.dialog_edit_text_editor) AlertDialog.Builder(this) - .setTitle(R.string.new_source) - .setView(view) - .setPositiveButton(android.R.string.yes, { _, _ -> - val newURL = edit.text.toString() - val parameterEditor = findViewById(R.id.setup_source_parameter) - parameterEditor.setText(newURL) - }) - .setNegativeButton(android.R.string.no, null) - .show() + .setTitle(R.string.new_source) + .setView(view) + .setPositiveButton(android.R.string.yes) { _, _ -> + val newURL = edit.text.toString() + val parameterEditor = findViewById(R.id.setup_source_parameter) + parameterEditor.setText(newURL) + } + .setNegativeButton(android.R.string.no, null) + .show() } } } @@ -175,26 +175,14 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener private fun validateParameter(id: Int, parameter: String): String? { return when (id) { - R.id.setup_method_online -> { - val result = URLAvailability.checkUrlAvailability(this, parameter) - return when (result) { - URLAvailability.ResultCode.URL_NO_INTERNET -> { - getString(R.string.setup_error_no_internet) - } - URLAvailability.ResultCode.URL_CONNECTION_FAILED -> { - getString(R.string.setup_error_connection_failed) - } - URLAvailability.ResultCode.URL_INVALID -> { - getString(R.string.setup_error_invalid_url) - } - else -> null - } + R.id.setup_method_online -> try { + java.net.URI.create(parameter) + null + } catch (e: IllegalArgumentException) { + getString(R.string.setup_error_invalid_url) } R.id.setup_method_local, - R.id.setup_method_backup -> { - if (File(parameter).exists()) null - else getString(R.string.setup_error_file_not_found) - } + R.id.setup_method_backup -> if (File(parameter).exists()) null else getString(R.string.setup_error_file_not_found) else -> null } } @@ -213,13 +201,13 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener val messageId = if (needSetup) R.string.setup_confirm_text else R.string.setup_reset_confirm_text AlertDialog.Builder(this) - .setTitle(titleId) - .setMessage(messageId) - .setPositiveButton(android.R.string.yes, { _, _ -> - doSetup(connection) - }) - .setNegativeButton(android.R.string.no, null) - .show() + .setTitle(titleId) + .setMessage(messageId) + .setPositiveButton(android.R.string.yes) { _, _ -> + doSetup(connection) + } + .setNegativeButton(android.R.string.no, null) + .show() } private fun doSetup(connection: SourceConnection) { @@ -234,22 +222,22 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener } else { AlertDialog.Builder(this) - .setTitle(R.string.error) - .setMessage(error.toString()) - .setNegativeButton(R.string.use_system_shell, { _, _ -> - setResult(RESULT_CANCELED) - finish() - }) - .setNeutralButton(R.string.show_help, { _, _ -> - App.get().openHelpLink() - }) - .setPositiveButton(android.R.string.yes, null) - .show() + .setTitle(R.string.error) + .setMessage(error.toString()) + .setNegativeButton(R.string.use_system_shell) { _, _ -> + setResult(RESULT_CANCELED) + finish() + } + .setNeutralButton(R.string.show_help) { _, _ -> + App.get().openHelpLink() + } + .setPositiveButton(android.R.string.yes, null) + .show() } } private fun executeAptUpdate() { - PackageUtils.apt(this, "update", null, { exitStatus, dialog -> + PackageUtils.apt(this, "update", null) { exitStatus, dialog -> if (exitStatus == 0) { dialog.dismiss() aptUpdated = true @@ -257,17 +245,17 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener } else { dialog.setTitle(getString(R.string.error)) } - }) + } } private fun executeAptUpgrade() { - PackageUtils.apt(this, "upgrade", arrayOf("-y"), { exitStatus, dialog -> + PackageUtils.apt(this, "upgrade", arrayOf("-y")) { exitStatus, dialog -> if (exitStatus == 0) { dialog.dismiss() finish() } else { dialog.setTitle(getString(R.string.error)) } - }) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/neoterm/utils/AssetsUtils.kt b/app/src/main/java/io/neoterm/utils/AssetsUtils.kt index 2a67b57..c9f05f6 100644 --- a/app/src/main/java/io/neoterm/utils/AssetsUtils.kt +++ b/app/src/main/java/io/neoterm/utils/AssetsUtils.kt @@ -2,7 +2,7 @@ package io.neoterm.utils import android.content.Context import java.io.File -import java.io.InputStream +import java.nio.file.Files /** * @author kiva @@ -10,18 +10,14 @@ import java.io.InputStream object AssetsUtils { fun extractAssetsDir(context: Context, dirName: String, extractDir: String) { val assets = context.assets - assets.list(dirName) - .map { File(extractDir, it) } + assets.list(dirName)?.let { + it.map { File(extractDir, it) } .takeWhile { !it.exists() } .forEach { file -> assets.open("$dirName/${file.name}").use { - FileUtils.writeFile(file, it) + kotlin.runCatching { Files.copy(it, file.toPath()) } } } - } - - fun openAssetsFile(context: Context, fileName: String) : InputStream { - val assets = context.assets - return assets.open(fileName) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/neoterm/utils/FileUtils.kt b/app/src/main/java/io/neoterm/utils/FileUtils.kt index 58c6af3..2e90f01 100644 --- a/app/src/main/java/io/neoterm/utils/FileUtils.kt +++ b/app/src/main/java/io/neoterm/utils/FileUtils.kt @@ -1,47 +1,11 @@ package io.neoterm.utils -import io.neoterm.frontend.logging.NLog -import java.io.File -import java.io.FileInputStream -import java.io.FileOutputStream -import java.io.InputStream import java.text.DecimalFormat /** * @author kiva */ object FileUtils { - fun writeFile(path: File, bytes: ByteArray): Boolean { - try { - return FileOutputStream(path).use { - it.write(bytes) - it.flush() - true - } - } catch (e: Exception) { - NLog.e("FileUtils", "Failed to write file: ${e.localizedMessage}") - return false - } - } - - fun writeFile(path: File, inputStream: InputStream): Boolean { - val bytes = ByteArray(inputStream.available()) - inputStream.read(bytes) - return writeFile(path, bytes) - } - - fun readFile(path: File): ByteArray? { - if (!path.canRead()) { - return null - } - - return FileInputStream(path).use { - val bytes = ByteArray(it.available()) - it.read(bytes) - bytes - } - } - fun formatSizeInKB(size: Long): String { val decimalFormat = DecimalFormat("####.00"); if (size < 1024) { diff --git a/app/src/main/java/io/neoterm/utils/MediaUtils.kt b/app/src/main/java/io/neoterm/utils/MediaUtils.kt index 2911bf3..912cbc9 100644 --- a/app/src/main/java/io/neoterm/utils/MediaUtils.kt +++ b/app/src/main/java/io/neoterm/utils/MediaUtils.kt @@ -15,8 +15,7 @@ import android.provider.MediaStore */ object MediaUtils { - @SuppressLint("ObsoleteSdkInt") - /** + /** * Get a file path from a Uri. This will get the the path for Storage Access * Framework Documents, as well as the _data field for the MediaStore and * other file-based ContentProviders. @@ -25,9 +24,10 @@ object MediaUtils { * * * @param uri The Uri to query. */ - fun getPath(context: Context, uri: Uri): String? { + @SuppressLint("ObsoleteSdkInt") + fun getPath(context: Context, uri: Uri?): String? { + uri ?: return null val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT - // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider @@ -44,37 +44,30 @@ object MediaUtils { return "/storage/$type/${split[1]}" } else if (isDownloadsDocument(uri)) { - val id = DocumentsContract.getDocumentId(uri) val contentUri = ContentUris.withAppendedId( - Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)!!) + Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)!! + ) return getDataColumn(context, contentUri, null, null) - } else if (isMediaDocument(uri)) { val docId = DocumentsContract.getDocumentId(uri) val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - val type = split[0] - var contentUri: Uri? = null - if ("image" == type) { - contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI - } else if ("video" == type) { - contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI - } else if ("audio" == type) { - contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + val contentUri = when (split[0]) { + "image" -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "video" -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI + "audio" -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + else -> null } val selection = "_id=?" val selectionArgs = arrayOf(split[1]) return getDataColumn(context, contentUri!!, selection, selectionArgs) - }// MediaProvider - // DownloadsProvider - + } } else if ("content".equals(uri.scheme, ignoreCase = true)) { return getDataColumn(context, uri, null, null) - } else if ("file".equals(uri.scheme, ignoreCase = true)) { return uri.path } @@ -96,8 +89,10 @@ object MediaUtils { * * * @return The value of the _data column, which is typically a file path. */ - private fun getDataColumn(context: Context, uri: Uri, selection: String?, - selectionArgs: Array?): String? { + private fun getDataColumn( + context: Context, uri: Uri, selection: String?, + selectionArgs: Array? + ): String? { var cursor: Cursor? = null val column = "_data" diff --git a/app/src/main/java/io/neoterm/utils/NetworkUtils.kt b/app/src/main/java/io/neoterm/utils/NetworkUtils.kt deleted file mode 100644 index 9d4269f..0000000 --- a/app/src/main/java/io/neoterm/utils/NetworkUtils.kt +++ /dev/null @@ -1,62 +0,0 @@ -package io.neoterm.utils - -import android.content.Context -import android.net.ConnectivityManager -import android.telephony.TelephonyManager - -/** - * @author kiva - */ -object NetworkUtils { - fun isNetworkAvailable(context: Context): Boolean { - return getNetworkType(context) != null - } - - private fun getNetworkType(context: Context): String? { - var networkType: String? = null - - val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager ?: return null - - val networkInfo = connectivityManager.activeNetworkInfo - - if (networkInfo != null && networkInfo.isConnected) { - if (networkInfo.type == ConnectivityManager.TYPE_WIFI) { - networkType = "WIFI" - - } else if (networkInfo.type == ConnectivityManager.TYPE_MOBILE) { - when (networkInfo.subtype) { - TelephonyManager.NETWORK_TYPE_GPRS, - TelephonyManager.NETWORK_TYPE_EDGE, - TelephonyManager.NETWORK_TYPE_CDMA, - TelephonyManager.NETWORK_TYPE_1xRTT, - TelephonyManager.NETWORK_TYPE_IDEN -> networkType = "2G" - - TelephonyManager.NETWORK_TYPE_UMTS, - TelephonyManager.NETWORK_TYPE_EVDO_0, - TelephonyManager.NETWORK_TYPE_EVDO_A, - TelephonyManager.NETWORK_TYPE_HSDPA, - TelephonyManager.NETWORK_TYPE_HSUPA, - TelephonyManager.NETWORK_TYPE_HSPA, - TelephonyManager.NETWORK_TYPE_EVDO_B, - TelephonyManager.NETWORK_TYPE_EHRPD, - TelephonyManager.NETWORK_TYPE_HSPAP -> networkType = "3G" - - TelephonyManager.NETWORK_TYPE_LTE -> networkType = "4G" - - else -> { - val subtypeName = networkInfo.subtypeName - if (subtypeName.equals("TD-SCDMA", ignoreCase = true) - || subtypeName.equals("WCDMA", ignoreCase = true) - || subtypeName.equals("CDMA2000", ignoreCase = true)) { - networkType = "3G" - } else { - networkType = subtypeName - } - } - } - } - } - - return networkType - } -} \ No newline at end of file diff --git a/app/src/main/java/io/neoterm/utils/PackageUtils.kt b/app/src/main/java/io/neoterm/utils/PackageUtils.kt index 36c2403..9f43f61 100644 --- a/app/src/main/java/io/neoterm/utils/PackageUtils.kt +++ b/app/src/main/java/io/neoterm/utils/PackageUtils.kt @@ -2,12 +2,8 @@ package io.neoterm.utils import android.content.Context import io.neoterm.backend.TerminalSession -import io.neoterm.component.pm.PackageComponent -import io.neoterm.component.pm.SourceManager -import io.neoterm.frontend.component.ComponentManager import io.neoterm.frontend.config.NeoTermPath import io.neoterm.frontend.floating.TerminalDialog -import java.io.File /** * @author kiva @@ -15,18 +11,18 @@ import java.io.File object PackageUtils { fun apt(context: Context, subCommand: String, extraArgs: Array?, callback: (Int, TerminalDialog) -> Unit) { val argArray = - if (extraArgs != null) arrayOf(NeoTermPath.APT_BIN_PATH, subCommand, *extraArgs) - else arrayOf(NeoTermPath.APT_BIN_PATH, subCommand) + if (extraArgs != null) arrayOf(NeoTermPath.APT_BIN_PATH, subCommand, *extraArgs) + else arrayOf(NeoTermPath.APT_BIN_PATH, subCommand) TerminalDialog(context) - .onFinish(object : TerminalDialog.SessionFinishedCallback { - override fun onSessionFinished(dialog: TerminalDialog, finishedSession: TerminalSession?) { - val exit = finishedSession?.exitStatus ?: 1 - callback(exit, dialog) - } - }) - .imeEnabled(true) - .execute(NeoTermPath.APT_BIN_PATH, argArray) - .show("apt $subCommand") + .onFinish(object : TerminalDialog.SessionFinishedCallback { + override fun onSessionFinished(dialog: TerminalDialog, finishedSession: TerminalSession?) { + val exit = finishedSession?.exitStatus ?: 1 + callback(exit, dialog) + } + }) + .imeEnabled(true) + .execute(NeoTermPath.APT_BIN_PATH, argArray) + .show("apt $subCommand") } } \ No newline at end of file diff --git a/app/src/main/java/io/neoterm/utils/TerminalUtils.kt b/app/src/main/java/io/neoterm/utils/TerminalUtils.kt index fca3ada..2a50840 100644 --- a/app/src/main/java/io/neoterm/utils/TerminalUtils.kt +++ b/app/src/main/java/io/neoterm/utils/TerminalUtils.kt @@ -1,7 +1,7 @@ package io.neoterm.utils -import androidx.appcompat.app.AppCompatActivity import android.content.Context +import androidx.appcompat.app.AppCompatActivity import io.neoterm.backend.TerminalSession import io.neoterm.component.font.FontComponent import io.neoterm.component.session.SessionComponent @@ -54,7 +54,7 @@ object TerminalUtils { val specialChars = "\"\\$`!" builder.append('"') val length = s.length - for (i in 0..length - 1) { + for (i in 0 until length) { val c = s[i] if (specialChars.indexOf(c) >= 0) { builder.append('\\')