mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-22 07:57:30 +00:00
Base backup restore activity.
This commit is contained in:
parent
0cd24905b7
commit
255271bfaf
@ -105,6 +105,11 @@
|
|||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
|
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
|
||||||
|
<activity
|
||||||
|
android:name="org.thoughtcrime.securesms.loki.activities.BackupRestoreActivity"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
|
android:windowSoftInputMode="adjustResize"
|
||||||
|
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.activities.LinkDeviceActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.LinkDeviceActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
|
15
build.gradle
15
build.gradle
@ -149,6 +149,8 @@ dependencies {
|
|||||||
implementation "com.fasterxml.jackson.core:jackson-databind:2.9.8"
|
implementation "com.fasterxml.jackson.core:jackson-databind:2.9.8"
|
||||||
implementation "com.squareup.okhttp3:okhttp:3.12.1"
|
implementation "com.squareup.okhttp3:okhttp:3.12.1"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
implementation 'androidx.fragment:fragment-ktx:1.3.0-beta01'
|
||||||
|
implementation 'androidx.activity:activity-ktx:1.1.0'
|
||||||
implementation "nl.komponents.kovenant:kovenant:$kovenant_version"
|
implementation "nl.komponents.kovenant:kovenant:$kovenant_version"
|
||||||
implementation "nl.komponents.kovenant:kovenant-android:$kovenant_version"
|
implementation "nl.komponents.kovenant:kovenant-android:$kovenant_version"
|
||||||
implementation "com.github.lelloman:android-identicons:v11"
|
implementation "com.github.lelloman:android-identicons:v11"
|
||||||
@ -347,6 +349,19 @@ android {
|
|||||||
includeAndroidResources = true
|
includeAndroidResources = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
dataBinding true
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = '1.8'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
95
res/layout/activity_backup_restore.xml
Normal file
95
res/layout/activity_backup_restore.xml
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<data>
|
||||||
|
<import type="org.thoughtcrime.securesms.loki.activities.RestoreBackupViewModel"/>
|
||||||
|
<import type="android.view.View"/>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="org.thoughtcrime.securesms.loki.activities.RestoreBackupViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
|
android:text="Restore from backup"
|
||||||
|
android:textColor="@color/text"
|
||||||
|
android:textSize="@dimen/large_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
|
android:text="Go on and pick the backup file to restore from."
|
||||||
|
android:textColor="@color/text"
|
||||||
|
android:textSize="@dimen/small_font_size" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonSelectFile"
|
||||||
|
style="@style/Button.Primary"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
|
android:text="@{RestoreBackupViewModel.uriToFileName(buttonSelectFile, viewModel.backupFile), default=`Select a file`}"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/backupCode"
|
||||||
|
style="@style/SmallSessionEditText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
|
android:hint="Backup code"
|
||||||
|
android:inputType="numberDecimal"
|
||||||
|
android:text="@={viewModel.backupPassphrase}" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/restoreButton"
|
||||||
|
style="@style/Widget.Session.Button.Common.ProminentFilled"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/medium_button_height"
|
||||||
|
android:layout_marginLeft="@dimen/massive_spacing"
|
||||||
|
android:layout_marginRight="@dimen/massive_spacing"
|
||||||
|
android:text="@string/continue_2"
|
||||||
|
android:visibility="@{RestoreBackupViewModel.validateData(viewModel.backupFile, viewModel.backupPassphrase) ? View.VISIBLE : View.INVISIBLE}"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/termsTextView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/onboarding_button_bottom_offset"
|
||||||
|
android:layout_marginLeft="@dimen/massive_spacing"
|
||||||
|
android:layout_marginRight="@dimen/massive_spacing"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="By using this service, you agree to our Terms of Service and Privacy Policy"
|
||||||
|
android:textColor="@color/text"
|
||||||
|
android:textColorLink="@color/text"
|
||||||
|
android:textSize="@dimen/very_small_font_size" /> <!-- Intentionally not yet translated -->
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</layout>
|
@ -49,6 +49,16 @@
|
|||||||
android:layout_marginRight="@dimen/massive_spacing"
|
android:layout_marginRight="@dimen/massive_spacing"
|
||||||
android:text="@string/activity_landing_restore_button_title" />
|
android:text="@string/activity_landing_restore_button_title" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style="@style/Widget.Session.Button.Common.ProminentOutline"
|
||||||
|
android:id="@+id/restoreBackupButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/medium_button_height"
|
||||||
|
android:layout_marginLeft="@dimen/massive_spacing"
|
||||||
|
android:layout_marginTop="@dimen/small_spacing"
|
||||||
|
android:layout_marginRight="@dimen/massive_spacing"
|
||||||
|
android:text="Backup" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/linkButton"
|
android:id="@+id/linkButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -5,6 +5,7 @@ import android.animation.Animator;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@ -328,7 +329,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
|
|
||||||
FullBackupImporter.importFile(context,
|
FullBackupImporter.importFile(context,
|
||||||
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
||||||
database, backup.getFile(), passphrase);
|
database, Uri.fromFile(backup.getFile()), passphrase);
|
||||||
|
|
||||||
DatabaseFactory.upgradeRestored(context, database);
|
DatabaseFactory.upgradeRestored(context, database);
|
||||||
NotificationChannels.restoreContactNotificationChannels(context);
|
NotificationChannels.restoreContactNotificationChannels(context);
|
||||||
|
@ -7,6 +7,8 @@ import android.content.Context;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import net.sqlcipher.database.SQLiteDatabase;
|
import net.sqlcipher.database.SQLiteDatabase;
|
||||||
@ -36,6 +38,7 @@ import org.thoughtcrime.securesms.util.Util;
|
|||||||
import org.whispersystems.libsignal.kdf.HKDFv3;
|
import org.whispersystems.libsignal.kdf.HKDFv3;
|
||||||
import org.whispersystems.libsignal.util.ByteUtil;
|
import org.whispersystems.libsignal.util.ByteUtil;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@ -63,13 +66,18 @@ public class FullBackupImporter extends FullBackupBase {
|
|||||||
private static final String TAG = FullBackupImporter.class.getSimpleName();
|
private static final String TAG = FullBackupImporter.class.getSimpleName();
|
||||||
|
|
||||||
public static void importFile(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret,
|
public static void importFile(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret,
|
||||||
@NonNull SQLiteDatabase db, @NonNull File file, @NonNull String passphrase)
|
@NonNull SQLiteDatabase db, @NonNull Uri fileUri, @NonNull String passphrase)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
BackupRecordInputStream inputStream = new BackupRecordInputStream(file, passphrase);
|
InputStream baseInputStream = context.getContentResolver().openInputStream(fileUri);
|
||||||
int count = 0;
|
if (baseInputStream == null) {
|
||||||
|
throw new IOException("Cannot open an input stream for the file URI: " + fileUri.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
try (BackupRecordInputStream inputStream = new BackupRecordInputStream(baseInputStream, passphrase)) {
|
||||||
|
|
||||||
try {
|
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
|
||||||
dropAllTables(db);
|
dropAllTables(db);
|
||||||
@ -91,7 +99,9 @@ public class FullBackupImporter extends FullBackupBase {
|
|||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
if (db.inTransaction()) {
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, count));
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, count));
|
||||||
@ -213,7 +223,7 @@ public class FullBackupImporter extends FullBackupBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class BackupRecordInputStream extends BackupStream {
|
private static class BackupRecordInputStream extends BackupStream implements Closeable {
|
||||||
|
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
private final Cipher cipher;
|
private final Cipher cipher;
|
||||||
@ -225,9 +235,9 @@ public class FullBackupImporter extends FullBackupBase {
|
|||||||
private byte[] iv;
|
private byte[] iv;
|
||||||
private int counter;
|
private int counter;
|
||||||
|
|
||||||
private BackupRecordInputStream(@NonNull File file, @NonNull String passphrase) throws IOException {
|
private BackupRecordInputStream(@NonNull InputStream inputStream, @NonNull String passphrase) throws IOException {
|
||||||
try {
|
try {
|
||||||
this.in = new FileInputStream(file);
|
this.in = inputStream;
|
||||||
|
|
||||||
byte[] headerLengthBytes = new byte[4];
|
byte[] headerLengthBytes = new byte[4];
|
||||||
Util.readFully(in, headerLengthBytes);
|
Util.readFully(in, headerLengthBytes);
|
||||||
@ -349,6 +359,11 @@ public class FullBackupImporter extends FullBackupBase {
|
|||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DatabaseDowngradeException extends IOException {
|
public static class DatabaseDowngradeException extends IOException {
|
||||||
|
@ -0,0 +1,231 @@
|
|||||||
|
package org.thoughtcrime.securesms.loki.activities
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.AsyncTask
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.OpenableColumns
|
||||||
|
import android.text.Spannable
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.text.style.ClickableSpan
|
||||||
|
import android.text.style.StyleSpan
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.core.widget.addTextChangedListener
|
||||||
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.google.android.gms.common.util.Strings
|
||||||
|
import kotlinx.android.synthetic.main.activity_pn_mode.*
|
||||||
|
import network.loki.messenger.R
|
||||||
|
import network.loki.messenger.databinding.ActivityBackupRestoreBinding
|
||||||
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
|
import org.thoughtcrime.securesms.RegistrationActivity
|
||||||
|
import org.thoughtcrime.securesms.backup.FullBackupImporter
|
||||||
|
import org.thoughtcrime.securesms.backup.FullBackupImporter.DatabaseDowngradeException
|
||||||
|
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
|
||||||
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
|
import org.thoughtcrime.securesms.logging.Log
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.show
|
||||||
|
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class BackupRestoreActivity : BaseActionBarActivity() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "BackupRestoreActivity"
|
||||||
|
private const val REQUEST_CODE_BACKUP_FILE = 779955
|
||||||
|
}
|
||||||
|
|
||||||
|
private val viewModel by viewModels<RestoreBackupViewModel>()
|
||||||
|
|
||||||
|
// region Lifecycle
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setUpActionBarSessionLogo()
|
||||||
|
val dataBinding = DataBindingUtil.setContentView<ActivityBackupRestoreBinding>(this, R.layout.activity_backup_restore)
|
||||||
|
dataBinding.lifecycleOwner = this
|
||||||
|
dataBinding.viewModel = viewModel
|
||||||
|
// setContentView(R.layout.activity_backup_restore)
|
||||||
|
|
||||||
|
dataBinding.restoreButton.setOnClickListener { restore() }
|
||||||
|
|
||||||
|
dataBinding.buttonSelectFile.setOnClickListener {
|
||||||
|
// Let user pick a file.
|
||||||
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||||
|
// type = BackupUtil.BACKUP_FILE_MIME_TYPE
|
||||||
|
type = "*/*"
|
||||||
|
}
|
||||||
|
startActivityForResult(intent, REQUEST_CODE_BACKUP_FILE)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataBinding.backupCode.addTextChangedListener { text -> viewModel.backupPassphrase.value = text.toString() }
|
||||||
|
|
||||||
|
//region Legal info views
|
||||||
|
val termsExplanation = SpannableStringBuilder("By using this service, you agree to our Terms of Service and Privacy Policy")
|
||||||
|
termsExplanation.setSpan(StyleSpan(Typeface.BOLD), 40, 56, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
termsExplanation.setSpan(object : ClickableSpan() {
|
||||||
|
|
||||||
|
override fun onClick(widget: View) {
|
||||||
|
openURL("https://getsession.org/terms-of-service/")
|
||||||
|
}
|
||||||
|
}, 40, 56, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
termsExplanation.setSpan(StyleSpan(Typeface.BOLD), 61, 75, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
termsExplanation.setSpan(object : ClickableSpan() {
|
||||||
|
|
||||||
|
override fun onClick(widget: View) {
|
||||||
|
openURL("https://getsession.org/privacy-policy/")
|
||||||
|
}
|
||||||
|
}, 61, 75, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
dataBinding.termsTextView.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
dataBinding.termsTextView.text = termsExplanation
|
||||||
|
//endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
|
||||||
|
when (requestCode) {
|
||||||
|
REQUEST_CODE_BACKUP_FILE -> {
|
||||||
|
if (resultCode == Activity.RESULT_OK && data != null && data.data != null) {
|
||||||
|
// // Acquire persistent access permissions for the file selected.
|
||||||
|
// val persistentFlags: Int = data.flags and
|
||||||
|
// (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
|
// context.contentResolver.takePersistableUriPermission(data.data!!, persistentFlags)
|
||||||
|
|
||||||
|
viewModel.onBackupFileSelected(data.data!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Interaction
|
||||||
|
private fun restore() {
|
||||||
|
if (viewModel.backupFile.value == null && Strings.isEmptyOrWhitespace(viewModel.backupPassphrase.value)) return
|
||||||
|
|
||||||
|
// val backupFile = viewModel.backupFile.value!!
|
||||||
|
// val password = viewModel.backupPassphrase.value!!.trim()
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// FullBackupImporter.importFile(
|
||||||
|
// this,
|
||||||
|
// AttachmentSecretProvider.getInstance(this).getOrCreateAttachmentSecret(),
|
||||||
|
// DatabaseFactory.getBackupDatabase(this),
|
||||||
|
// backupFile,
|
||||||
|
// password
|
||||||
|
// )
|
||||||
|
// } catch (e: IOException) {
|
||||||
|
// Log.e(TAG, "Failed to restore from the backup file \"$backupFile\"", e)
|
||||||
|
// }
|
||||||
|
|
||||||
|
val backupFile = viewModel.backupFile.value!!
|
||||||
|
val passphrase = viewModel.backupPassphrase.value!!.trim()
|
||||||
|
|
||||||
|
object : AsyncTask<Void?, Void?, BackupImportResult>() {
|
||||||
|
override fun doInBackground(vararg params: Void?): BackupImportResult {
|
||||||
|
return try {
|
||||||
|
val context: Context = this@BackupRestoreActivity
|
||||||
|
val database = DatabaseFactory.getBackupDatabase(context)
|
||||||
|
FullBackupImporter.importFile(
|
||||||
|
context,
|
||||||
|
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
||||||
|
DatabaseFactory.getBackupDatabase(context),
|
||||||
|
backupFile,
|
||||||
|
passphrase
|
||||||
|
)
|
||||||
|
DatabaseFactory.upgradeRestored(context, database)
|
||||||
|
NotificationChannels.restoreContactNotificationChannels(context)
|
||||||
|
TextSecurePreferences.setBackupEnabled(context, true)
|
||||||
|
TextSecurePreferences.setBackupPassphrase(context, passphrase)
|
||||||
|
BackupImportResult.SUCCESS
|
||||||
|
} catch (e: DatabaseDowngradeException) {
|
||||||
|
Log.w(TAG, "Failed due to the backup being from a newer version of Signal.", e)
|
||||||
|
BackupImportResult.FAILURE_VERSION_DOWNGRADE
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.w(TAG, e)
|
||||||
|
BackupImportResult.FAILURE_UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPostExecute(result: BackupImportResult) {
|
||||||
|
val context = this@BackupRestoreActivity
|
||||||
|
when (result) {
|
||||||
|
BackupImportResult.SUCCESS -> {
|
||||||
|
TextSecurePreferences.setHasSeenWelcomeScreen(context, true)
|
||||||
|
TextSecurePreferences.setPromptedPushRegistration(context, true)
|
||||||
|
TextSecurePreferences.setIsUsingFCM(context, true)
|
||||||
|
TextSecurePreferences.setHasSeenMultiDeviceRemovalSheet(context)
|
||||||
|
TextSecurePreferences.setHasSeenLightThemeIntroSheet(context)
|
||||||
|
val application = ApplicationContext.getInstance(context)
|
||||||
|
application.setUpStorageAPIIfNeeded()
|
||||||
|
application.setUpP2PAPIIfNeeded()
|
||||||
|
|
||||||
|
val intent = Intent(context, HomeActivity::class.java)
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
show(intent)
|
||||||
|
}
|
||||||
|
BackupImportResult.FAILURE_VERSION_DOWNGRADE ->
|
||||||
|
Toast.makeText(context, R.string.RegistrationActivity_backup_failure_downgrade, Toast.LENGTH_LONG).show()
|
||||||
|
BackupImportResult.FAILURE_UNKNOWN ->
|
||||||
|
Toast.makeText(context, R.string.RegistrationActivity_incorrect_backup_passphrase, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openURL(url: String) {
|
||||||
|
try {
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||||
|
startActivity(intent)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(this, R.string.invalid_url, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum class BackupImportResult {
|
||||||
|
SUCCESS, FAILURE_VERSION_DOWNGRADE, FAILURE_UNKNOWN
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
class RestoreBackupViewModel(application: Application): AndroidViewModel(application) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun uriToFileName(view: View, fileUri: Uri?): String? {
|
||||||
|
fileUri ?: return null
|
||||||
|
|
||||||
|
view.context.contentResolver.query(fileUri, null, null, null, null).use {
|
||||||
|
val nameIndex = it!!.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||||
|
it.moveToFirst()
|
||||||
|
return it.getString(nameIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun validateData(fileUri: Uri?, passphrase: String?): Boolean {
|
||||||
|
return fileUri != null && !Strings.isEmptyOrWhitespace(passphrase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val backupFile = MutableLiveData<Uri>()
|
||||||
|
val backupPassphrase = MutableLiveData<String>()
|
||||||
|
|
||||||
|
fun onBackupFileSelected(backupFile: Uri) {
|
||||||
|
//TODO Check if backup file is correct.
|
||||||
|
this.backupFile.value = backupFile
|
||||||
|
}
|
||||||
|
}
|
@ -44,6 +44,10 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega
|
|||||||
fakeChatView.startAnimating()
|
fakeChatView.startAnimating()
|
||||||
registerButton.setOnClickListener { register() }
|
registerButton.setOnClickListener { register() }
|
||||||
restoreButton.setOnClickListener { restore() }
|
restoreButton.setOnClickListener { restore() }
|
||||||
|
restoreBackupButton.setOnClickListener {
|
||||||
|
val intent = Intent(this, BackupRestoreActivity::class.java)
|
||||||
|
push(intent)
|
||||||
|
}
|
||||||
// linkButton.setOnClickListener { linkDevice() }
|
// linkButton.setOnClickListener { linkDevice() }
|
||||||
if (TextSecurePreferences.getWasUnlinked(this)) {
|
if (TextSecurePreferences.getWasUnlinked(this)) {
|
||||||
Toast.makeText(this, R.string.activity_landing_device_unlinked_dialog_title, Toast.LENGTH_LONG).show()
|
Toast.makeText(this, R.string.activity_landing_device_unlinked_dialog_title, Toast.LENGTH_LONG).show()
|
||||||
|
@ -28,6 +28,7 @@ import kotlin.jvm.Throws
|
|||||||
|
|
||||||
object BackupUtil {
|
object BackupUtil {
|
||||||
private const val TAG = "BackupUtil"
|
private const val TAG = "BackupUtil"
|
||||||
|
const val BACKUP_FILE_MIME_TYPE = "application/x-binary"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set app-wide configuration to enable the backups and schedule them.
|
* Set app-wide configuration to enable the backups and schedule them.
|
||||||
@ -151,7 +152,7 @@ object BackupUtil {
|
|||||||
val fileUri = DocumentsContract.createDocument(
|
val fileUri = DocumentsContract.createDocument(
|
||||||
context.contentResolver,
|
context.contentResolver,
|
||||||
DocumentFile.fromTreeUri(context, dirUri)!!.uri,
|
DocumentFile.fromTreeUri(context, dirUri)!!.uri,
|
||||||
"application/x-binary",
|
BACKUP_FILE_MIME_TYPE,
|
||||||
fileName)
|
fileName)
|
||||||
|
|
||||||
if (fileUri == null) {
|
if (fileUri == null) {
|
||||||
@ -160,7 +161,7 @@ object BackupUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FullBackupExporter.export(context,
|
FullBackupExporter.export(context,
|
||||||
AttachmentSecretProvider.getInstance(context).orCreateAttachmentSecret,
|
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
||||||
DatabaseFactory.getBackupDatabase(context),
|
DatabaseFactory.getBackupDatabase(context),
|
||||||
fileUri,
|
fileUri,
|
||||||
backupPassword)
|
backupPassword)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user