Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import/Export encryption and progress notification #317

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ import com.simplemobiletools.smsmessenger.adapters.ConversationsAdapter
import com.simplemobiletools.smsmessenger.dialogs.ExportMessagesDialog
import com.simplemobiletools.smsmessenger.dialogs.ImportMessagesDialog
import com.simplemobiletools.smsmessenger.extensions.*
import com.simplemobiletools.smsmessenger.helpers.EXPORT_MIME_TYPE
import com.simplemobiletools.smsmessenger.helpers.MessagesExporter
import com.simplemobiletools.smsmessenger.helpers.THREAD_ID
import com.simplemobiletools.smsmessenger.helpers.THREAD_TITLE
import com.simplemobiletools.smsmessenger.helpers.*
import com.simplemobiletools.smsmessenger.models.Conversation
import com.simplemobiletools.smsmessenger.models.Events
import kotlinx.android.synthetic.main.activity_main.*
Expand All @@ -37,7 +34,7 @@ import org.greenrobot.eventbus.ThreadMode
import java.io.FileOutputStream
import java.io.OutputStream
import java.util.*
import kotlin.collections.ArrayList


class MainActivity : SimpleActivity() {
private val MAKE_DEFAULT_APP_REQUEST = 1
Expand Down Expand Up @@ -367,7 +364,7 @@ class MainActivity : SimpleActivity() {
if (isQPlus()) {
ExportMessagesDialog(this, config.lastExportPath, true) { file ->
Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
type = EXPORT_MIME_TYPE
type = if (config.exportBackupPassword != "") EXPORT_SECURE_MIME_TYPE else EXPORT_MIME_TYPE
putExtra(Intent.EXTRA_TITLE, file.name)
addCategory(Intent.CATEGORY_OPENABLE)
startActivityForResult(this, PICK_EXPORT_FILE_INTENT)
Expand All @@ -388,12 +385,17 @@ class MainActivity : SimpleActivity() {

private fun exportMessagesTo(outputStream: OutputStream?) {
toast(R.string.exporting)
val exportNotification = ImportExportProgressNotification(this, ImportExportProgressNotification.ImportOrExport.EXPORT)
ensureBackgroundThread {
smsExporter.exportMessages(outputStream) {
exportNotification.spawnProgressNotification()
smsExporter.exportMessages(outputStream, { state, total, current ->
exportNotification.updateNotification(state, total, current)
}) {
val toastId = when (it) {
MessagesExporter.ExportResult.EXPORT_OK -> R.string.exporting_successful
else -> R.string.exporting_failed
}
exportNotification.setFinish(it == MessagesExporter.ExportResult.EXPORT_OK)

toast(toastId)
}
Expand All @@ -404,7 +406,7 @@ class MainActivity : SimpleActivity() {
if (isQPlus()) {
Intent(Intent.ACTION_GET_CONTENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = EXPORT_MIME_TYPE
type = "*/*"
startActivityForResult(this, PICK_IMPORT_SOURCE_INTENT)
}
} else {
Expand All @@ -423,7 +425,8 @@ class MainActivity : SimpleActivity() {
}

private fun showImportEventsDialog(path: String) {
ImportMessagesDialog(this, path)
val importNotification = ImportExportProgressNotification(this, ImportExportProgressNotification.ImportOrExport.IMPORT)
ImportMessagesDialog(this, path, importNotification)
}

private fun tryImportMessagesFromFile(uri: Uri) {
Expand All @@ -435,7 +438,6 @@ class MainActivity : SimpleActivity() {
toast(R.string.unknown_error_occurred)
return
}

try {
val inputStream = contentResolver.openInputStream(uri)
val out = FileOutputStream(tempFile)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.extensions.config
import com.simplemobiletools.smsmessenger.helpers.EXPORT_FILE_EXT
import com.simplemobiletools.smsmessenger.helpers.EXPORT_SECURE_FILE_EXT
import kotlinx.android.synthetic.main.dialog_export_messages.view.*
import java.io.File

Expand Down Expand Up @@ -51,7 +52,9 @@ class ExportMessagesDialog(
when {
filename.isEmpty() -> activity.toast(R.string.empty_name)
filename.isAValidFilename() -> {
val file = File(realPath, "$filename$EXPORT_FILE_EXT")
config.exportBackupPassword = view.export_messages_password.value //We need to get this early to set proper extension
val exportFileExtension = if (config.exportBackupPassword == "") EXPORT_FILE_EXT else EXPORT_SECURE_FILE_EXT
val file = File(realPath, "$filename$exportFileExtension")
if (!hidePath && file.exists()) {
activity.toast(R.string.name_taken)
return@setOnClickListener
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.value
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.extensions.config
import com.simplemobiletools.smsmessenger.helpers.ImportExportProgressNotification
import com.simplemobiletools.smsmessenger.helpers.MessagesImporter
import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_OK
import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_PARTIAL
Expand All @@ -16,6 +18,7 @@ import kotlinx.android.synthetic.main.dialog_import_messages.view.*
class ImportMessagesDialog(
private val activity: SimpleActivity,
private val path: String,
private val importNotification: ImportExportProgressNotification,
) {

private val config = activity.config
Expand Down Expand Up @@ -43,11 +46,14 @@ class ImportMessagesDialog(
}

ignoreClicks = true
importNotification.spawnProgressNotification()
activity.toast(R.string.importing)
config.importSms = view.import_sms_checkbox.isChecked
config.importMms = view.import_mms_checkbox.isChecked
config.importBackupPassword = view.import_messages_password.value
ensureBackgroundThread {
MessagesImporter(activity).importMessages(path) {
MessagesImporter(activity).importMessages(path,
{ state, total, current -> importNotification.updateNotification(state, total, current) }) {
handleParseResult(it)
dismiss()
}
Expand All @@ -65,5 +71,6 @@ class ImportMessagesDialog(
else -> R.string.no_items_found
}
)
importNotification.setFinish(result == IMPORT_OK)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getString(LAST_EXPORT_PATH, "")!!
set(lastExportPath) = prefs.edit().putString(LAST_EXPORT_PATH, lastExportPath).apply()

var exportBackupPassword: String
get() = prefs.getString(EXPORT_BACKUP_PASSWORD, "")!!
set(exportBackupPassword) = prefs.edit().putString(EXPORT_BACKUP_PASSWORD, exportBackupPassword).apply()

var exportSms: Boolean
get() = prefs.getBoolean(EXPORT_SMS, true)
set(exportSms) = prefs.edit().putBoolean(EXPORT_SMS, exportSms).apply()
Expand All @@ -72,6 +76,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getBoolean(EXPORT_MMS, true)
set(exportMms) = prefs.edit().putBoolean(EXPORT_MMS, exportMms).apply()

var importBackupPassword: String
get() = prefs.getString(IMPORT_BACKUP_PASSWORD, "")!!
set(importBackupPassword) = prefs.edit().putString(IMPORT_BACKUP_PASSWORD, importBackupPassword).apply()

var importSms: Boolean
get() = prefs.getBoolean(IMPORT_SMS, true)
set(importSms) = prefs.edit().putBoolean(IMPORT_SMS, importSms).apply()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,22 @@ const val SEND_LONG_MESSAGE_MMS = "send_long_message_mms"
const val MMS_FILE_SIZE_LIMIT = "mms_file_size_limit"
const val PINNED_CONVERSATIONS = "pinned_conversations"
const val LAST_EXPORT_PATH = "last_export_path"
const val EXPORT_BACKUP_PASSWORD = "export_backup_password"
const val EXPORT_SMS = "export_sms"
const val EXPORT_MMS = "export_mms"
const val EXPORT_MIME_TYPE = "application/json"
const val EXPORT_SECURE_MIME_TYPE = "application/sec"
const val EXPORT_FILE_EXT = ".json"
const val EXPORT_SECURE_FILE_EXT = ".sec"
const val IMPORT_BACKUP_PASSWORD = "import_backup_password"
const val IMPORT_SMS = "import_sms"
const val IMPORT_MMS = "import_mms"
const val WAS_DB_CLEARED = "was_db_cleared"

//Secure Backup Cipher Parameters
const val KEY_ITERATIONS = 65536
const val KEY_LENGTH = 256

private const val PATH = "com.simplemobiletools.smsmessenger.action."
const val MARK_AS_READ = PATH + "mark_as_read"
const val REPLY = PATH + "reply"
Expand All @@ -45,6 +53,9 @@ const val LOCK_SCREEN_SENDER_MESSAGE = 1
const val LOCK_SCREEN_SENDER = 2
const val LOCK_SCREEN_NOTHING = 3

//Notifications
const val EXPORT_IMPORT_NOTIFICATION_ID = 33

const val FILE_SIZE_NONE = -1L
const val FILE_SIZE_100_KB = 102_400L
const val FILE_SIZE_200_KB = 204_800L
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package com.simplemobiletools.smsmessenger.helpers

import android.app.*
import android.content.Context.NOTIFICATION_SERVICE
import androidx.core.app.NotificationCompat
import com.simplemobiletools.commons.helpers.isOreoPlus
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import java.util.*

class ImportExportProgressNotification(
private val activity: SimpleActivity,
private val type: ImportOrExport
) {
enum class ImportOrExport {
IMPORT, EXPORT
}

private var isInit = false
private lateinit var notification: NotificationCompat.Builder
private lateinit var channelId: String
private val progressMax = 100
private val notificationManager = activity.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
private var waitTime = 0L
private var startTime = 0L

init {
startTime = System.currentTimeMillis()
if (isOreoPlus()) {
channelId = activity.getString(R.string.channel_import_export)
val name = activity.getString(R.string.channel_import_export)
val importance = NotificationManager.IMPORTANCE_LOW
val mChannel = NotificationChannel(channelId, name, importance)

notificationManager.createNotificationChannel(mChannel)
}
}

fun setFinish(hasSucceed: Boolean) {
if (isInit) {
isInit = false
val contentTitle =
if (type == ImportOrExport.EXPORT) activity.getString(R.string.exporting_successful) else activity.getString(R.string.importing_successful)
notification.setContentTitle(contentTitle)

if (hasSucceed) {
notification.setContentText("Success")
.setProgress(0, 0, false)
.setOngoing(false)
.setAutoCancel(true)
} else {
notification.setContentText("Something went wrong")
.setProgress(0, 0, false)
.setOngoing(false)
.setAutoCancel(true)
}
notificationManager.notify(EXPORT_IMPORT_NOTIFICATION_ID, notification.build())
}
}

fun spawnProgressNotification() {
val contentTitle =
if (type == ImportOrExport.IMPORT) activity.getString(R.string.importing_messages) else activity.getString(R.string.exporting_messages)
//Creating a notification and setting its various attributes
notification =
NotificationCompat.Builder(activity, channelId)
.setSmallIcon(R.drawable.ic_messenger)
.setContentTitle(contentTitle)
.setContentText("0%")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setOngoing(true)
.setProgress(progressMax, 0, false)

notificationManager.notify(EXPORT_IMPORT_NOTIFICATION_ID, notification.build())
isInit = true
}

fun updateNotification(state: Any, total: Int, current: Int) {
if (isInit) {
if (waitTime > 500) {
if (total > 1 && current <= total && current > 0) {
val progress = current.toDouble() / total * 100.00
notification.setContentText(progress.toInt().toString() + "%")
.setProgress(progressMax, progress.toInt(), false)
}

if (type == ImportOrExport.EXPORT) {
when (state) {
MessagesExporter.ExportState.EXPORT -> notification.setContentTitle(activity.getString(R.string.exporting_messages))
MessagesExporter.ExportState.ENCRYPT -> notification.setContentTitle(activity.getString(R.string.encrypting_backup))
}
} else {
when (state) {
MessagesImporter.ImportState.DECRYPTING -> {
notification.setContentTitle(activity.getString(R.string.decrypting_backup))
.setProgress(100, 50, true)
}
MessagesImporter.ImportState.RESTORING -> notification.setContentTitle(activity.getString(R.string.importing_messages))
}
}

notificationManager.notify(EXPORT_IMPORT_NOTIFICATION_ID, notification.build())
startTime = System.currentTimeMillis()
waitTime = 0L
} else {
waitTime = Date().time - startTime
}
}
}
}
Loading