From e17ffc85e7a6482f0fdc2c6532f95d8af3c493e4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Jun 2019 14:59:54 +0200 Subject: [PATCH] KeysBackup: save recovery key to file --- .../riotredesign/core/files/FileSaver.kt | 60 +++++++++++++++++++ .../setup/KeysBackupSetupStep3Fragment.kt | 48 ++++++++------- 2 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotredesign/core/files/FileSaver.kt diff --git a/vector/src/main/java/im/vector/riotredesign/core/files/FileSaver.kt b/vector/src/main/java/im/vector/riotredesign/core/files/FileSaver.kt new file mode 100644 index 0000000000..e855d3b28f --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/files/FileSaver.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotredesign.core.files + +import android.app.DownloadManager +import android.content.Context +import okio.Okio +import timber.log.Timber +import java.io.File + +/** + * Save a string to a file with Okio + * @return true in case of success + */ +fun saveStringToFile(str: String, file: File): Boolean { + return try { + val sink = Okio.sink(file) + + val bufferedSink = Okio.buffer(sink) + + bufferedSink.writeString(str, Charsets.UTF_8) + + bufferedSink.close() + sink.close() + + true + } catch (e: Exception) { + Timber.e(e, "Error saving file") + false + } +} + + +fun addEntryToDownloadManager(context: Context, + file: File, + mimeType: String, + title: String = file.name, + description: String = file.name) { + val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager? + + try { + downloadManager?.addCompletedDownload(title, description, true, mimeType, file.absolutePath, file.length(), true) + } catch (e: Exception) { + Timber.e(e, "## addEntryToDownloadManager(): Exception") + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt index d6a96426d6..a951b4c178 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt @@ -16,10 +16,12 @@ package im.vector.riotredesign.features.crypto.keysbackup.setup import android.os.Bundle +import android.os.Environment import android.view.View import android.widget.Button import android.widget.TextView import android.widget.Toast +import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders @@ -28,9 +30,11 @@ import butterknife.OnClick import com.google.android.material.bottomsheet.BottomSheetDialog import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel import im.vector.riotredesign.R +import im.vector.riotredesign.core.files.addEntryToDownloadManager +import im.vector.riotredesign.core.files.saveStringToFile import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.core.utils.* -import java.io.ByteArrayInputStream +import java.io.File class KeysBackupSetupStep3Fragment : VectorBaseFragment() { @@ -152,28 +156,32 @@ class KeysBackupSetupStep3Fragment : VectorBaseFragment() { } } - fun exportRecoveryKeyToFile(it: String) { - val stream = ByteArrayInputStream(it.toByteArray()) + private fun exportRecoveryKeyToFile(data: String) { + val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + val file = File(parentDir, "recovery-key-" + System.currentTimeMillis() + ".txt") - vectorBaseActivity.notImplemented("export recovery key to file") - /* - val url = viewModel.session.mediaCache.saveMedia(stream, "recovery-key" + System.currentTimeMillis() + ".txt", "text/plain") - stream.close() - CommonActivityUtils.saveMediaIntoDownloads(context, - File(Uri.parse(url).path!!), "recovery-key.txt", "text/plain", object : SimpleApiCallback() { - override fun onSuccess(path: String) { - context?.let { - AlertDialog.Builder(it) - .setMessage(getString(R.string.recovery_key_export_saved_as_warning, path)) - .setCancelable(false) - .setPositiveButton(R.string.ok, null) - .show() - } + if (saveStringToFile(data, file)) { + addEntryToDownloadManager(requireContext(), file, "text/plain") - viewModel.copyHasBeenMade = true + context?.let { + AlertDialog.Builder(it) + .setMessage(getString(R.string.recovery_key_export_saved_as_warning, file.absolutePath)) + .setCancelable(false) + .setPositiveButton(R.string.ok, null) + .show() } - }) - */ + + viewModel.copyHasBeenMade = true + } else { + context?.let { + AlertDialog.Builder(it) + .setTitle(R.string.dialog_title_error) + .setMessage(getString(R.string.unknown_error)) + .setCancelable(false) + .setPositiveButton(R.string.ok, null) + .show() + } + } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {