From 2410b0827e9d6fcd7b9dfd3c762425eb63d0aba4 Mon Sep 17 00:00:00 2001 From: TranceLove Date: Mon, 5 Aug 2024 15:19:19 +0800 Subject: [PATCH] SftpConnectDialog: Wrap open DocumentsUI intent with Intent.createChooser() to get PEM content To fix regressions in newer Androids that SftpConnectDialog unable to load PEM for SSH authentication. Reference: https://stackoverflow.com/questions/10002065/android-gallery-always-returns-result-canceled-to-onactivityresult --- .../ui/dialogs/SftpConnectDialog.kt | 445 ++++++++++-------- .../ui/dialogs/SftpConnectDialogTest.kt | 63 +-- build.gradle | 3 +- gradle/libs.versions.toml | 2 +- 4 files changed, 276 insertions(+), 237 deletions(-) diff --git a/app/src/main/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialog.kt b/app/src/main/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialog.kt index e707128bd7..d919961ff4 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialog.kt +++ b/app/src/main/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialog.kt @@ -86,9 +86,7 @@ import java.util.concurrent.Callable /** SSH/SFTP connection setup dialog. */ class SftpConnectDialog : DialogFragment() { - companion object { - @JvmStatic private val log: Logger = LoggerFactory.getLogger(SftpConnectDialog::class.java) @@ -139,29 +137,33 @@ class SftpConnectDialog : DialogFragment() { val accentColor = (activity as ThemedActivity).accent - // Use system provided action to get Uri to PEM. + // Use system provided action to get Uri to PEM (mostly via DocumentsUI). binding.selectPemBTN.setOnClickListener { - val intent = Intent() - .setType(MimeTypes.ALL_MIME_TYPES) - .setAction(Intent.ACTION_GET_CONTENT) - activityResultHandlerForPemSelection.launch(intent) + val intent = + Intent() + .setType(MimeTypes.ALL_MIME_TYPES) + .setAction(Intent.ACTION_GET_CONTENT) + activityResultHandlerForPemSelection.launch( + Intent.createChooser(intent, getString(R.string.ssh_select_pem)) + ) } // Define action for buttons - val dialogBuilder = MaterialDialog.Builder(ctx.get()!!) - .title(R.string.scp_connection) - .autoDismiss(false) - .customView(binding.root, true) - .theme(utilsProvider.appTheme.getMaterialDialogTheme()) - .negativeText(R.string.cancel) - .positiveText(if (edit) R.string.update else R.string.create) - .positiveColor(accentColor) - .negativeColor(accentColor) - .neutralColor(accentColor) - .onPositive(handleOnPositiveButton(edit)) - .onNegative { dialog: MaterialDialog, _: DialogAction? -> - dialog.dismiss() - } + val dialogBuilder = + MaterialDialog.Builder(ctx.get()!!) + .title(R.string.scp_connection) + .autoDismiss(false) + .customView(binding.root, true) + .theme(utilsProvider.appTheme.getMaterialDialogTheme()) + .negativeText(R.string.cancel) + .positiveText(if (edit) R.string.update else R.string.create) + .positiveColor(accentColor) + .negativeColor(accentColor) + .neutralColor(accentColor) + .onPositive(handleOnPositiveButton(edit)) + .onNegative { dialog: MaterialDialog, _: DialogAction? -> + dialog.dismiss() + } // If we are editing connection settings, give new actions for neutral and negative buttons if (edit) { @@ -181,113 +183,122 @@ class SftpConnectDialog : DialogFragment() { return dialog } - private fun initForm(edit: Boolean) = binding.run { - portET.apply { - filters = arrayOf(MinMaxInputFilter(VALID_PORT_RANGE)) - // For convenience, so I don't need to press backspace all the time - onFocusChangeListener = View.OnFocusChangeListener { _: View?, hasFocus: Boolean -> - if (hasFocus) { - selectAll() - } + @Suppress("ComplexMethod", "LongMethod") + private fun initForm(edit: Boolean) = + binding.run { + portET.apply { + filters = arrayOf(MinMaxInputFilter(VALID_PORT_RANGE)) + // For convenience, so I don't need to press backspace all the time + onFocusChangeListener = + View.OnFocusChangeListener { _: View?, hasFocus: Boolean -> + if (hasFocus) { + selectAll() + } + } } - } - protocolDropDown.adapter = ArrayAdapter( - requireContext(), - android.R.layout.simple_spinner_dropdown_item, - requireContext().resources.getStringArray(R.array.ftpProtocols) - ) - chkFtpAnonymous.setOnCheckedChangeListener { _, isChecked -> - usernameET.isEnabled = !isChecked - passwordET.isEnabled = !isChecked - if (isChecked) { - usernameET.setText("") - passwordET.setText("") + protocolDropDown.adapter = + ArrayAdapter( + requireContext(), + android.R.layout.simple_spinner_dropdown_item, + requireContext().resources.getStringArray(R.array.ftpProtocols) + ) + chkFtpAnonymous.setOnCheckedChangeListener { _, isChecked -> + usernameET.isEnabled = !isChecked + passwordET.isEnabled = !isChecked + if (isChecked) { + usernameET.setText("") + passwordET.setText("") + } } - } - defaultPathET.filters = arrayOf(defaultPathCharFilter) - // If it's new connection setup, set some default values - // Otherwise, use given Bundle instance for filling in the blanks - if (!edit) { - connectionET.setText(R.string.scp_connection) - portET.setText(NetCopyClientConnectionPool.SSH_DEFAULT_PORT.toString()) - protocolDropDown.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected( - parent: AdapterView<*>?, - view: View?, - position: Int, - id: Long - ) { - portET.setText( - when (position) { - 1 -> NetCopyClientConnectionPool.FTP_DEFAULT_PORT.toString() - 2 -> NetCopyClientConnectionPool.FTPS_DEFAULT_PORT.toString() - else -> NetCopyClientConnectionPool.SSH_DEFAULT_PORT.toString() + defaultPathET.filters = arrayOf(defaultPathCharFilter) + // If it's new connection setup, set some default values + // Otherwise, use given Bundle instance for filling in the blanks + if (!edit) { + connectionET.setText(R.string.scp_connection) + portET.setText(NetCopyClientConnectionPool.SSH_DEFAULT_PORT.toString()) + protocolDropDown.onItemSelectedListener = + object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long + ) { + portET.setText( + when (position) { + 1 -> NetCopyClientConnectionPool.FTP_DEFAULT_PORT.toString() + 2 -> NetCopyClientConnectionPool.FTPS_DEFAULT_PORT.toString() + else -> NetCopyClientConnectionPool.SSH_DEFAULT_PORT.toString() + } + ) + chkFtpAnonymous.visibility = + when (position) { + 0 -> View.GONE + else -> View.VISIBLE + } + if (position == 0) { + chkFtpAnonymous.isChecked = false + } + selectPemBTN.visibility = + when (position) { + 0 -> View.VISIBLE + else -> View.GONE + } } - ) - chkFtpAnonymous.visibility = when (position) { - 0 -> View.GONE - else -> View.VISIBLE - } - if (position == 0) { - chkFtpAnonymous.isChecked = false + + override fun onNothingSelected(parent: AdapterView<*>?) = Unit } - selectPemBTN.visibility = when (position) { - 0 -> View.VISIBLE - else -> View.GONE + } else { + protocolDropDown.setSelection( + when (requireArguments().getString(ARG_PROTOCOL)) { + FTP_URI_PREFIX -> 1 + FTPS_URI_PREFIX -> 2 + else -> 0 } + ) + connectionET.setText(requireArguments().getString(ARG_NAME)) + ipET.setText(requireArguments().getString(ARG_ADDRESS)) + portET.setText(requireArguments().getInt(ARG_PORT).toString()) + defaultPathET.setText(requireArguments().getString(ARG_DEFAULT_PATH)) + usernameET.setText(requireArguments().getString(ARG_USERNAME)) + if (requireArguments().getBoolean(ARG_HAS_PASSWORD)) { + passwordET.setHint(R.string.password_unchanged) + } else { + selectedParsedKeyPairName = requireArguments().getString(ARG_KEYPAIR_NAME) + selectPemBTN.text = selectedParsedKeyPairName } - override fun onNothingSelected(parent: AdapterView<*>?) = Unit - } - } else { - protocolDropDown.setSelection( - when (requireArguments().getString(ARG_PROTOCOL)) { - FTP_URI_PREFIX -> 1 - FTPS_URI_PREFIX -> 2 - else -> 0 - } - ) - connectionET.setText(requireArguments().getString(ARG_NAME)) - ipET.setText(requireArguments().getString(ARG_ADDRESS)) - portET.setText(requireArguments().getInt(ARG_PORT).toString()) - defaultPathET.setText(requireArguments().getString(ARG_DEFAULT_PATH)) - usernameET.setText(requireArguments().getString(ARG_USERNAME)) - if (requireArguments().getBoolean(ARG_HAS_PASSWORD)) { - passwordET.setHint(R.string.password_unchanged) - } else { - selectedParsedKeyPairName = requireArguments().getString(ARG_KEYPAIR_NAME) - selectPemBTN.text = selectedParsedKeyPairName + oldPath = + NetCopyClientUtils.deriveUriFrom( + requireArguments().getString(ARG_PROTOCOL)!!, + requireArguments().getString(ARG_ADDRESS)!!, + requireArguments().getInt(ARG_PORT), + requireArguments().getString(ARG_DEFAULT_PATH, ""), + requireArguments().getString(ARG_USERNAME)!!, + requireArguments().getString(ARG_PASSWORD), + edit + ) } - oldPath = NetCopyClientUtils.deriveUriFrom( - requireArguments().getString(ARG_PROTOCOL)!!, - requireArguments().getString(ARG_ADDRESS)!!, - requireArguments().getInt(ARG_PORT), - requireArguments().getString(ARG_DEFAULT_PATH, ""), - requireArguments().getString(ARG_USERNAME)!!, - requireArguments().getString(ARG_PASSWORD), - edit - ) } - } - private fun appendButtonListenersForEdit( - dialogBuilder: MaterialDialog.Builder - ) { + private fun appendButtonListenersForEdit(dialogBuilder: MaterialDialog.Builder) { createConnectionSettings(edit = true).run { dialogBuilder .negativeText(R.string.delete) .onNegative { dialog: MaterialDialog, _: DialogAction? -> - val path = NetCopyClientUtils.deriveUriFrom( - getProtocolPrefixFromDropdownSelection(), - hostname, - port, - defaultPath, - username, - requireArguments().getString(ARG_PASSWORD, null), - edit = true - ) - val i = DataUtils.getInstance().containsServer( - arrayOf(connectionName, path) - ) + val path = + NetCopyClientUtils.deriveUriFrom( + getProtocolPrefixFromDropdownSelection(), + hostname, + port, + defaultPath, + username, + requireArguments().getString(ARG_PASSWORD, null), + edit = true + ) + val i = + DataUtils.getInstance().containsServer( + arrayOf(connectionName, path) + ) if (i > -1) { DataUtils.getInstance().removeServer(i) AppConfig.getInstance() @@ -311,26 +322,32 @@ class SftpConnectDialog : DialogFragment() { } } - private fun createValidator(edit: Boolean, okBTN: MDButton): SimpleTextWatcher { + private fun createValidator( + edit: Boolean, + okBTN: MDButton + ): SimpleTextWatcher { return object : SimpleTextWatcher() { override fun afterTextChanged(s: Editable) { val portETValue = binding.portET.text.toString() - val port = if (portETValue.isDigitsOnly() && (portETValue.length in 1..5)) { - portETValue.toInt() - } else { - -1 - } - val hasCredential: Boolean = if (edit) { - if (true == binding.passwordET.text?.isNotEmpty() || - !TextUtils.isEmpty(requireArguments().getString(ARG_PASSWORD)) - ) { - true + val port = + if (portETValue.isDigitsOnly() && (portETValue.length in 1..5)) { + portETValue.toInt() } else { - true == selectedParsedKeyPairName?.isNotEmpty() + -1 + } + val hasCredential: Boolean = + if (edit) { + if (true == binding.passwordET.text?.isNotEmpty() || + !TextUtils.isEmpty(requireArguments().getString(ARG_PASSWORD)) + ) { + true + } else { + true == selectedParsedKeyPairName?.isNotEmpty() + } + } else { + true == binding.passwordET.text?.isNotEmpty() || + selectedParsedKeyPair != null } - } else { - true == binding.passwordET.text?.isNotEmpty() || selectedParsedKeyPair != null - } okBTN.isEnabled = ( true == binding.connectionET.text?.isNotEmpty() && true == binding.ipET.text?.isNotEmpty() && @@ -345,8 +362,7 @@ class SftpConnectDialog : DialogFragment() { } } - private fun handleOnPositiveButton(edit: Boolean): - MaterialDialog.SingleButtonCallback = + private fun handleOnPositiveButton(edit: Boolean): MaterialDialog.SingleButtonCallback = MaterialDialog.SingleButtonCallback { _, _ -> createConnectionSettings(edit).run { when (prefix) { @@ -356,7 +372,10 @@ class SftpConnectDialog : DialogFragment() { } } - private fun positiveButtonForFtp(connectionSettings: ConnectionSettings, edit: Boolean) { + private fun positiveButtonForFtp( + connectionSettings: ConnectionSettings, + edit: Boolean + ) { connectionSettings.run { authenticateAndSaveSetup(connectionSettings = connectionSettings, isEdit = edit) } @@ -365,7 +384,10 @@ class SftpConnectDialog : DialogFragment() { /* * for SSH and FTPS, get host's cert/public key fingerprint. */ - private fun positiveButtonForSftp(connectionSettings: ConnectionSettings, edit: Boolean) { + private fun positiveButtonForSftp( + connectionSettings: ConnectionSettings, + edit: Boolean + ) { connectionSettings.run { // Get original SSH host key AppConfig.getInstance().utilsHandler.getRemoteHostKey( @@ -412,7 +434,8 @@ class SftpConnectDialog : DialogFragment() { hostAndPort, hostKeyAlgorithm, hostKeyFingerprint, - hostInfo -> + hostInfo + -> AlertDialog.Builder(ctx.get()) .setTitle(R.string.ssh_host_key_verification_prompt_title) .setMessage( @@ -584,73 +607,77 @@ class SftpConnectDialog : DialogFragment() { } @Suppress("LabeledExpression") - private val activityResultHandlerForPemSelection = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { - if (Activity.RESULT_OK == it.resultCode) { - it.data?.data?.run { - selectedPem = this - runCatching { - requireContext().contentResolver.openInputStream(this)?.let { - selectedKeyContent -> - val observable = PemToKeyPairObservable(selectedKeyContent) - create(observable).subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .retryWhen { exceptions -> - exceptions.flatMap { exception -> - create { subscriber -> - observable.displayPassphraseDialog(exception, { - subscriber.onNext(Unit) - }, { - subscriber.onError(exception) - }) + private val activityResultHandlerForPemSelection = + registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { + if (Activity.RESULT_OK == it.resultCode) { + it.data?.data?.run { + selectedPem = this + runCatching { + requireContext().contentResolver.openInputStream(this)?.let { + selectedKeyContent -> + val observable = PemToKeyPairObservable(selectedKeyContent) + create(observable).subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .retryWhen { exceptions -> + exceptions.flatMap { exception -> + create { subscriber -> + observable.displayPassphraseDialog(exception, { + subscriber.onNext(Unit) + }, { + subscriber.onError(exception) + }) + } } } - } - .subscribe({ result -> - selectedParsedKeyPair = result - selectedParsedKeyPairName = this - .lastPathSegment!! - .substring( - this.lastPathSegment!! - .indexOf('/') + 1 - ) - val okBTN = (dialog as MaterialDialog) - .getActionButton(DialogAction.POSITIVE) - okBTN.isEnabled = okBTN.isEnabled || true - binding.selectPemBTN.text = selectedParsedKeyPairName - }, {}) + .subscribe({ result -> + selectedParsedKeyPair = result + selectedParsedKeyPairName = + this + .lastPathSegment!! + .substring( + this.lastPathSegment!! + .indexOf('/') + 1 + ) + val okBTN = + (dialog as MaterialDialog) + .getActionButton(DialogAction.POSITIVE) + okBTN.isEnabled = okBTN.isEnabled || true + binding.selectPemBTN.text = selectedParsedKeyPairName + }, {}) + } + }.onFailure { + log.error("Error reading PEM key", it) } - }.onFailure { - log.error("Error reading PEM key", it) } } } - } private fun authenticateAndSaveSetup( connectionSettings: ConnectionSettings, hostKeyFingerprint: String? = null, isEdit: Boolean - ): Boolean = connectionSettings.run { - val path = this.toUriString() - val encryptedPath = NetCopyClientUtils.encryptFtpPathAsNecessary(path) - return if (!isEdit) { - saveFtpConnectionAndLoadlist( - connectionSettings, - hostKeyFingerprint, - encryptedPath, - selectedParsedKeyPairName, - selectedParsedKeyPair - ) - } else { - updateFtpConnection( - connectionName, - hostKeyFingerprint, - encryptedPath - ) + ): Boolean = + connectionSettings.run { + val path = this.toUriString() + val encryptedPath = NetCopyClientUtils.encryptFtpPathAsNecessary(path) + return if (!isEdit) { + saveFtpConnectionAndLoadlist( + connectionSettings, + hostKeyFingerprint, + encryptedPath, + selectedParsedKeyPairName, + selectedParsedKeyPair + ) + } else { + updateFtpConnection( + connectionName, + hostKeyFingerprint, + encryptedPath + ) + } } - } @Suppress("LongParameterList") private fun saveFtpConnectionAndLoadlist( @@ -746,13 +773,14 @@ class SftpConnectDialog : DialogFragment() { } // Read the PEM content from InputStream to String. - private fun getPemContents(): String? = selectedPem?.run { - runCatching { - requireContext().contentResolver.openInputStream(this) - ?.bufferedReader() - ?.use(BufferedReader::readText) - }.getOrNull() - } + private fun getPemContents(): String? = + selectedPem?.run { + runCatching { + requireContext().contentResolver.openInputStream(this) + ?.bufferedReader() + ?.use(BufferedReader::readText) + }.getOrNull() + } private fun getProtocolPrefixFromDropdownSelection(): String { return when (binding.protocolDropDown.selectedItem.toString()) { @@ -773,14 +801,15 @@ class SftpConnectDialog : DialogFragment() { val selectedParsedKeyPairName: String? = null, val selectedParsedKeyPair: KeyPair? = null ) { - fun toUriString() = NetCopyClientUtils.deriveUriFrom( - prefix, - hostname, - port, - defaultPath, - username, - password - ) + fun toUriString() = + NetCopyClientUtils.deriveUriFrom( + prefix, + hostname, + port, + defaultPath, + username, + password + ) } // FIXME: username/password may not need urlEncoded during edit mode @@ -789,7 +818,8 @@ class SftpConnectDialog : DialogFragment() { prefix = getProtocolPrefixFromDropdownSelection(), connectionName = binding.connectionET.text.toString(), hostname = binding.ipET.text.toString(), - port = binding.portET.text.toString().let { + port = + binding.portET.text.toString().let { if (it.isEmpty() || it.isBlank()) { SSH_DEFAULT_PORT } else { @@ -798,7 +828,8 @@ class SftpConnectDialog : DialogFragment() { }, defaultPath = binding.defaultPathET.text.toString(), username = binding.usernameET.text.toString().urlEncoded(), - password = if (true == binding.passwordET.text?.isEmpty()) { + password = + if (true == binding.passwordET.text?.isEmpty()) { if (edit) { requireArguments().getString(ARG_PASSWORD, null)?.run { PasswordUtil.decryptPassword(AppConfig.getInstance(), this) diff --git a/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogTest.kt b/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogTest.kt index fc8db02b62..49aff3dffe 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogTest.kt @@ -48,7 +48,6 @@ import java.util.concurrent.TimeUnit @Suppress("StringLiteralDuplication") class SftpConnectDialogTest : AbstractMainActivityTestBase() { - private lateinit var mc: MockedConstruction /** @@ -57,12 +56,13 @@ class SftpConnectDialogTest : AbstractMainActivityTestBase() { @Before override fun setUp() { super.setUp() - mc = mockConstruction( - SftpConnectDialog::class.java - ) { mock: SftpConnectDialog, _: MockedConstruction.Context? -> - doCallRealMethod().`when`(mock).arguments = any() - `when`(mock.arguments).thenCallRealMethod() - } + mc = + mockConstruction( + SftpConnectDialog::class.java + ) { mock: SftpConnectDialog, _: MockedConstruction.Context? -> + doCallRealMethod().`when`(mock).arguments = any() + `when`(mock.arguments).thenCallRealMethod() + } } /** @@ -116,9 +116,10 @@ class SftpConnectDialogTest : AbstractMainActivityTestBase() { */ @Test fun testInvokeSftpConnectionDialogWithPasswordAndDefaultPath() { - val uri = NetCopyClientUtils.encryptFtpPathAsNecessary( - "ssh://root:12345678@127.0.0.1:22/data/incoming" - ) + val uri = + NetCopyClientUtils.encryptFtpPathAsNecessary( + "ssh://root:12345678@127.0.0.1:22/data/incoming" + ) val verify = Bundle() verify.putString("address", "127.0.0.1") verify.putInt("port", 22) @@ -138,13 +139,15 @@ class SftpConnectDialogTest : AbstractMainActivityTestBase() { /** * Test invoke [SftpConnectDialog] with arguments including password and URL encoded path. */ + @Suppress("ktlint:standard:max-line-length", "ktlint:standard:no-single-line-block-comment") @Test @Throws(GeneralSecurityException::class, IOException::class) fun testInvokeSftpConnectionDialogWithPasswordAndEncodedDefaultPath() { /* ktlint-disable max-line-length */ - val uri = NetCopyClientUtils.encryptFtpPathAsNecessary( - "ssh://root:12345678@127.0.0.1:22/Users/TranceLove/My+Documents/%7BReference%7D%20Zobius%20Facro%20%24%24%20%23RFII1" - ) + val uri = + NetCopyClientUtils.encryptFtpPathAsNecessary( + "ssh://root:12345678@127.0.0.1:22/Users/TranceLove/My+Documents/%7BReference%7D%20Zobius%20Facro%20%24%24%20%23RFII1" + ) /* ktlint-enable max-line-length */ val verify = Bundle() verify.putString("address", "127.0.0.1") @@ -166,7 +169,10 @@ class SftpConnectDialogTest : AbstractMainActivityTestBase() { } @Throws(GeneralSecurityException::class, IOException::class) - private fun testOpenSftpConnectDialog(uri: String, verify: Bundle) { + private fun testOpenSftpConnectDialog( + uri: String, + verify: Bundle + ) { val activity = mock(MainActivity::class.java) val utilsHandler = mock(UtilsHandler::class.java) `when`(utilsHandler.getSshAuthPrivateKeyName("ssh://root@127.0.0.1:22")) @@ -186,15 +192,15 @@ class SftpConnectDialogTest : AbstractMainActivityTestBase() { val mocked = mc.constructed()[0] await().atMost(10, TimeUnit.SECONDS).until { mocked.arguments != null } for (key in BUNDLE_KEYS) { - if (mocked.arguments!![key] != null) { + if (mocked.arguments?.getString(key) != null) { if (key != "password") { - assertEquals(verify[key], mocked.arguments!![key]) + assertEquals(verify.getString(key), mocked.arguments?.getString(key)) } else { assertEquals( - verify[key], + verify.getString(key), PasswordUtil.decryptPassword( ApplicationProvider.getApplicationContext(), - (mocked.arguments!![key] as String?)!!, + requireNotNull(mocked.arguments?.getString(key)), Base64.URL_SAFE ) ) @@ -205,15 +211,16 @@ class SftpConnectDialogTest : AbstractMainActivityTestBase() { companion object { @JvmStatic - private val BUNDLE_KEYS = arrayOf( - "address", - "port", - "keypairName", - "name", - "username", - "password", - "edit", - "defaultPath" - ) + private val BUNDLE_KEYS = + arrayOf( + "address", + "port", + "keypairName", + "name", + "username", + "password", + "edit", + "defaultPath" + ) } } diff --git a/build.gradle b/build.gradle index 8e38989935..2dd1fac3ff 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,7 @@ allprojects { mavenCentral() maven { url "https://jitpack.io" } maven { url "https://jcenter.bintray.com" } + maven { url "https://repository.liferay.com/nexus/content/repositories/public/"} } tasks.withType(Test).tap { configureEach { @@ -149,7 +150,7 @@ subprojects { } } dependencies { - compileOnly 'com.github.pengrad:jdk9-deps:1.0' +// compileOnly 'com.github.pengrad:jdk9-deps:1.0' if (project.hasProperty('kapt')) { kapt 'javax.xml.bind:jaxb-api:2.3.1' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d1f93a268d..df771680e3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ glide = "4.14.2" sshj = "0.35.0" jcifs = "2.1.9" eventbus = "3.3.1" -fabSpeedDial = "3.1.1" +fabSpeedDial = "3.3.0" room = "2.5.2" bouncyCastle = "1.76" awaitility = "3.1.6"