diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupDialog.java b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupDialog.java index 2715311d54..3722a52bbe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupDialog.java +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupDialog.java @@ -6,6 +6,8 @@ import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Build; +import android.provider.DocumentsContract; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; @@ -21,7 +23,6 @@ import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.components.SwitchPreferenceCompat; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.registration.fragments.RestoreBackupFragment; @@ -31,8 +32,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.text.AfterTextChanged; -import java.util.Objects; - public class BackupDialog { private static final String TAG = Log.tag(BackupDialog.class); @@ -119,6 +118,10 @@ public class BackupDialog { .setPositiveButton(R.string.BackupDialog_choose_folder, ((dialog, which) -> { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + if (Build.VERSION.SDK_INT >= 26) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, SignalStore.settings().getLatestSignalBackupDirectory()); + } + intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java index a089c6e819..08481dfd36 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java @@ -11,7 +11,8 @@ public final class SettingsValues extends SignalStoreValues { public static final String LINK_PREVIEWS = "settings.link_previews"; public static final String KEEP_MESSAGES_DURATION = "settings.keep_messages_duration"; - private static final String SIGNAL_BACKUP_DIRECTORY = "settings.signal.backup.directory"; + private static final String SIGNAL_BACKUP_DIRECTORY = "settings.signal.backup.directory"; + private static final String SIGNAL_LATEST_BACKUP_DIRECTORY = "settings.signal.backup.directory,latest"; public static final String THREAD_TRIM_LENGTH = "pref_trim_length"; public static final String THREAD_TRIM_ENABLED = "pref_trim_threads"; @@ -61,11 +62,23 @@ public final class SettingsValues extends SignalStoreValues { public void setSignalBackupDirectory(@NonNull Uri uri) { putString(SIGNAL_BACKUP_DIRECTORY, uri.toString()); + putString(SIGNAL_LATEST_BACKUP_DIRECTORY, uri.toString()); } - public @Nullable - Uri getSignalBackupDirectory() { - String uri = getString(SIGNAL_BACKUP_DIRECTORY, ""); + public @Nullable Uri getSignalBackupDirectory() { + return getUri(SIGNAL_BACKUP_DIRECTORY); + } + + public @Nullable Uri getLatestSignalBackupDirectory() { + return getUri(SIGNAL_LATEST_BACKUP_DIRECTORY); + } + + public void clearSignalBackupDirectory() { + putString(SIGNAL_BACKUP_DIRECTORY, null); + } + + private @Nullable Uri getUri(@NonNull String key) { + String uri = getString(key, ""); if (TextUtils.isEmpty(uri)) { return null; @@ -73,8 +86,4 @@ public final class SettingsValues extends SignalStoreValues { return Uri.parse(uri); } } - - public void clearSignalBackupDirectory() { - putString(SIGNAL_BACKUP_DIRECTORY, null); - } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/BackupsPreferenceFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/BackupsPreferenceFragment.java index ec1dd5af57..6e1042fd61 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/BackupsPreferenceFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/BackupsPreferenceFragment.java @@ -4,6 +4,7 @@ import android.Manifest; import android.app.Activity; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; @@ -102,17 +103,15 @@ public class BackupsPreferenceFragment extends Fragment { @Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - if (requestCode == CHOOSE_BACKUPS_LOCATION_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null && data.getData() != null) { - - DocumentFile backupDirectory = DocumentFile.fromTreeUri(requireContext(), data.getData()); - if (backupDirectory == null || !backupDirectory.isDirectory()) { - Log.w(TAG, "Could not open backup directory."); - return; - } - + if (Build.VERSION.SDK_INT >= 29 && + requestCode == CHOOSE_BACKUPS_LOCATION_REQUEST_CODE && + resultCode == Activity.RESULT_OK && + data != null && + data.getData() != null) + { BackupDialog.showEnableBackupDialog(requireContext(), data, - backupDirectory.getName(), + StorageUtil.getDisplayPath(requireContext(), data.getData()), this::setBackupsEnabled); } } @@ -159,13 +158,10 @@ public class BackupsPreferenceFragment extends Fragment { if (BackupUtil.isUserSelectionRequired(requireContext()) && BackupUtil.canUserAccessBackupDirectory(requireContext())) { - Uri backupUri = Objects.requireNonNull(SignalStore.settings().getSignalBackupDirectory()); - DocumentFile backupFile = Objects.requireNonNull(DocumentFile.fromTreeUri(requireContext(), backupUri)); + Uri backupUri = Objects.requireNonNull(SignalStore.settings().getSignalBackupDirectory()); - if (backupFile.getName() != null) { - folder.setVisibility(View.VISIBLE); - folderName.setText(backupFile.getName()); - } + folder.setVisibility(View.VISIBLE); + folderName.setText(StorageUtil.getDisplayPath(requireContext(), backupUri)); } else if (StorageUtil.canWriteInSignalStorageDir()) { try { folder.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/ChooseBackupFragment.java b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/ChooseBackupFragment.java index 2c5d463eb0..7b08b6315e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/ChooseBackupFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/ChooseBackupFragment.java @@ -2,7 +2,9 @@ package org.thoughtcrime.securesms.registration.fragments; import android.app.Activity; import android.content.Intent; +import android.os.Build; import android.os.Bundle; +import android.provider.DocumentsContract; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.View; @@ -20,8 +22,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.util.BackupUtil; -import java.util.Objects; - public class ChooseBackupFragment extends BaseRegistrationFragment { private static final String TAG = Log.tag(ChooseBackupFragment.class); @@ -71,6 +71,10 @@ public class ChooseBackupFragment extends BaseRegistrationFragment { intent.setType("application/octet-stream"); + if (Build.VERSION.SDK_INT >= 26) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, SignalStore.settings().getLatestSignalBackupDirectory()); + } + startActivityForResult(intent, OPEN_FILE_REQUEST_CODE); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RestoreBackupFragment.java b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RestoreBackupFragment.java index 20cbe19cf3..401695de88 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RestoreBackupFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RestoreBackupFragment.java @@ -8,7 +8,9 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; +import android.provider.DocumentsContract; import android.text.Editable; import android.text.Spanned; import android.text.TextWatcher; @@ -26,6 +28,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog; +import androidx.documentfile.provider.DocumentFile; import androidx.navigation.Navigation; import com.dd.CircularProgressButton; @@ -49,6 +52,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.service.LocalBackupListener; import org.thoughtcrime.securesms.util.BackupUtil; import org.thoughtcrime.securesms.util.DateUtils; +import org.thoughtcrime.securesms.util.StorageUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.concurrent.SimpleTask; diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ServiceUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ServiceUtil.java index 9094063412..f6413f0e37 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ServiceUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ServiceUtil.java @@ -19,6 +19,7 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; +import android.os.storage.StorageManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.view.WindowManager; @@ -34,6 +35,10 @@ public class ServiceUtil { return (WindowManager) context.getSystemService(Activity.WINDOW_SERVICE); } + public static StorageManager getStorageManager(Context context) { + return ContextCompat.getSystemService(context, StorageManager.class); + } + public static ConnectivityManager getConnectivityManager(Context context) { return (ConnectivityManager) context.getSystemService(Activity.CONNECTIVITY_SERVICE); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/StorageUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/StorageUtil.java index a84457401f..07297bf22c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/StorageUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/StorageUtil.java @@ -5,17 +5,24 @@ import android.content.Context; import android.net.Uri; import android.os.Build; import android.os.Environment; +import android.os.storage.StorageManager; +import android.os.storage.StorageVolume; import android.provider.MediaStore; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import org.thoughtcrime.securesms.BuildConfig; +import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.NoExternalStorageException; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; +import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.permissions.Permissions; import java.io.File; +import java.util.List; +import java.util.Objects; public class StorageUtil { @@ -45,6 +52,30 @@ public class StorageUtil { return backups; } + @RequiresApi(24) + public static @NonNull String getDisplayPath(@NonNull Context context, @NonNull Uri uri) { + String lastPathSegment = Objects.requireNonNull(uri.getLastPathSegment()); + String backupVolume = lastPathSegment.replaceFirst(":.*", ""); + String backupName = lastPathSegment.replaceFirst(".*:", ""); + + StorageManager storageManager = ServiceUtil.getStorageManager(context); + List storageVolumes = storageManager.getStorageVolumes(); + StorageVolume storageVolume = null; + + for (StorageVolume volume : storageVolumes) { + if (Objects.equals(volume.getUuid(), backupVolume)) { + storageVolume = volume; + break; + } + } + + if (storageVolume == null) { + return backupName; + } else { + return context.getString(R.string.StorageUtil__s_s, storageVolume.getDescription(context), backupName); + } + } + public static File getBackupCacheDirectory(Context context) { return context.getExternalCacheDir(); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 953787449a..953b92c1b1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2750,6 +2750,9 @@ Voice message · %1$s %1$s to %2$s + + %1$s/%2$s +