use new storage location for backup and recordings

Daniel Gultsch created

Change summary

src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java |  11 
src/main/java/eu/siacs/conversations/persistance/FileBackend.java               | 111 
src/main/java/eu/siacs/conversations/services/ExportBackupService.java          |   6 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java               |   4 
src/main/java/eu/siacs/conversations/ui/RecordingActivity.java                  |  22 
src/main/java/eu/siacs/conversations/ui/SettingsActivity.java                   |   2 
6 files changed, 61 insertions(+), 95 deletions(-)

Detailed changes

src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java 🔗

@@ -128,16 +128,19 @@ public class ImportBackupService extends Service {
             final List<Jid> accounts = mDatabaseBackend.getAccountJids(false);
             final ArrayList<BackupFile> backupFiles = new ArrayList<>();
             final Set<String> apps = new HashSet<>(Arrays.asList("Conversations", "Quicksy", getString(R.string.app_name)));
-            for (String app : apps) {
-                final File directory = new File(FileBackend.getBackupDirectory(app));
+            final List<File> directories = new ArrayList<>();
+            for (final String app : apps) {
+                directories.add(FileBackend.getLegacyBackupDirectory(app));
+            }
+            directories.add(FileBackend.getBackupDirectory(this));
+            for (final File directory : directories) {
                 if (!directory.exists() || !directory.isDirectory()) {
                     Log.d(Config.LOGTAG, "directory not found: " + directory.getAbsolutePath());
                     continue;
                 }
                 final File[] files = directory.listFiles();
                 if (files == null) {
-                    onBackupFilesLoaded.onBackupFilesLoaded(backupFiles);
-                    return;
+                    continue;
                 }
                 for (final File file : files) {
                     if (file.isFile() && file.getName().endsWith(".ceb")) {

src/main/java/eu/siacs/conversations/persistance/FileBackend.java 🔗

@@ -64,7 +64,6 @@ import eu.siacs.conversations.entities.DownloadableFile;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.services.AttachFileToConversationRunnable;
 import eu.siacs.conversations.services.XmppConnectionService;
-import eu.siacs.conversations.ui.RecordingActivity;
 import eu.siacs.conversations.ui.util.Attachment;
 import eu.siacs.conversations.utils.Compatibility;
 import eu.siacs.conversations.utils.CryptoHelper;
@@ -88,19 +87,6 @@ public class FileBackend {
         this.mXmppConnectionService = service;
     }
 
-    private static boolean isInDirectoryThatShouldNotBeScanned(Context context, File file) {
-        return isInDirectoryThatShouldNotBeScanned(context, file.getAbsolutePath());
-    }
-
-    public static boolean isInDirectoryThatShouldNotBeScanned(Context context, String path) {
-        for (String type : new String[] {RecordingActivity.STORAGE_DIRECTORY_TYPE_NAME, "Files"}) {
-            if (path.startsWith(getLegacyStorageLocation(context, type).getAbsolutePath())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     public static long getFileSize(Context context, Uri uri) {
         try {
             final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
@@ -156,34 +142,18 @@ public class FileBackend {
         return true;
     }
 
-    public static File getLegacyStorageLocation(Context context, final String type) {
-        if (Config.ONLY_INTERNAL_STORAGE) {
-            return new File(context.getFilesDir(), type);
-        } else {
-            final File appDirectory =
-                    new File(
-                            Environment.getExternalStorageDirectory(),
-                            context.getString(R.string.app_name));
-            final File appMediaDirectory = new File(appDirectory, "Media");
-            final String locationName =
-                    String.format("%s %s", context.getString(R.string.app_name), type);
-            return new File(appMediaDirectory, locationName);
-        }
-    }
-
-    private static String getAppMediaDirectory(Context context) {
-        return Environment.getExternalStorageDirectory().getAbsolutePath()
-                + "/"
-                + context.getString(R.string.app_name)
-                + "/Media/";
-    }
-
-    public static String getBackupDirectory(Context context) {
-        return getBackupDirectory(context.getString(R.string.app_name));
+    public static File getBackupDirectory(final Context context) {
+        final File conversationsDownloadDirectory =
+                new File(
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_DOWNLOADS),
+                        context.getString(R.string.app_name));
+        return new File(conversationsDownloadDirectory, "Backup");
     }
 
-    public static String getBackupDirectory(String app) {
-        return Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + app + "/Backup/";
+    public static File getLegacyBackupDirectory(final String app) {
+        final File appDirectory = new File(Environment.getExternalStorageDirectory(), app);
+        return new File(appDirectory, "Backup");
     }
 
     private static Bitmap rotate(final Bitmap bitmap, final int degree) {
@@ -521,38 +491,26 @@ public class FileBackend {
     }
 
     public void updateMediaScanner(File file, final Runnable callback) {
-        if (!isInDirectoryThatShouldNotBeScanned(mXmppConnectionService, file)) {
-            MediaScannerConnection.scanFile(
-                    mXmppConnectionService,
-                    new String[] {file.getAbsolutePath()},
-                    null,
-                    new MediaScannerConnection.MediaScannerConnectionClient() {
-                        @Override
-                        public void onMediaScannerConnected() {}
-
-                        @Override
-                        public void onScanCompleted(String path, Uri uri) {
-                            if (callback != null && file.getAbsolutePath().equals(path)) {
+        MediaScannerConnection.scanFile(
+                mXmppConnectionService,
+                new String[] {file.getAbsolutePath()},
+                null,
+                new MediaScannerConnection.MediaScannerConnectionClient() {
+                    @Override
+                    public void onMediaScannerConnected() {}
+
+                    @Override
+                    public void onScanCompleted(String path, Uri uri) {
+                        if (callback != null && file.getAbsolutePath().equals(path)) {
+                            callback.run();
+                        } else {
+                            Log.d(Config.LOGTAG, "media scanner scanned wrong file");
+                            if (callback != null) {
                                 callback.run();
-                            } else {
-                                Log.d(Config.LOGTAG, "media scanner scanned wrong file");
-                                if (callback != null) {
-                                    callback.run();
-                                }
                             }
                         }
-                    });
-            return;
-            /*Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
-            intent.setData(Uri.fromFile(file));
-            mXmppConnectionService.sendBroadcast(intent);*/
-        } else if (file.getAbsolutePath()
-                .startsWith(getAppMediaDirectory(mXmppConnectionService))) {
-            createNoMedia(file.getParentFile());
-        }
-        if (callback != null) {
-            callback.run();
-        }
+                    }
+                });
     }
 
     public boolean deleteFile(Message message) {
@@ -629,9 +587,20 @@ public class FileBackend {
         return attachments;
     }
 
-    // TODO remove static method. use direct instance access
     private File getLegacyStorageLocation(final String type) {
-        return getLegacyStorageLocation(mXmppConnectionService, type);
+        if (Config.ONLY_INTERNAL_STORAGE) {
+            return new File(mXmppConnectionService.getFilesDir(), type);
+        } else {
+            final File appDirectory =
+                    new File(
+                            Environment.getExternalStorageDirectory(),
+                            mXmppConnectionService.getString(R.string.app_name));
+            final File appMediaDirectory = new File(appDirectory, "Media");
+            final String locationName =
+                    String.format(
+                            "%s %s", mXmppConnectionService.getString(R.string.app_name), type);
+            return new File(appMediaDirectory, locationName);
+        }
     }
 
     private Bitmap resize(final Bitmap originalBitmap, int size) throws IOException {

src/main/java/eu/siacs/conversations/services/ExportBackupService.java 🔗

@@ -291,7 +291,7 @@ public class ExportBackupService extends Service {
             secureRandom.nextBytes(salt);
             final BackupFileHeader backupFileHeader = new BackupFileHeader(getString(R.string.app_name), account.getJid(), System.currentTimeMillis(), IV, salt);
             final Progress progress = new Progress(mBuilder, max, count);
-            final File file = new File(FileBackend.getBackupDirectory(this) + account.getJid().asBareJid().toEscapedString() + ".ceb");
+            final File file = new File(FileBackend.getBackupDirectory(this), account.getJid().asBareJid().toEscapedString() + ".ceb");
             files.add(file);
             final File directory = file.getParentFile();
             if (directory != null && directory.mkdirs()) {
@@ -335,7 +335,7 @@ public class ExportBackupService extends Service {
     }
 
     private void notifySuccess(final List<File> files) {
-        final String path = FileBackend.getBackupDirectory(this);
+        final String path = FileBackend.getBackupDirectory(this).getAbsolutePath();
 
         PendingIntent openFolderIntent = null;
 
@@ -363,7 +363,7 @@ public class ExportBackupService extends Service {
         NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
         mBuilder.setContentTitle(getString(R.string.notification_backup_created_title))
                 .setContentText(getString(R.string.notification_backup_created_subtitle, path))
-                .setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.notification_backup_created_subtitle, FileBackend.getBackupDirectory(this))))
+                .setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.notification_backup_created_subtitle, FileBackend.getBackupDirectory(this).getAbsolutePath())))
                 .setAutoCancel(true)
                 .setContentIntent(openFolderIntent)
                 .setSmallIcon(R.drawable.ic_archive_white_24dp);

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -1183,8 +1183,8 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
                 cancelTransmission.setVisible(true);
             }
             if (m.isFileOrImage() && !deleted && !cancelable) {
-                String path = m.getRelativeFilePath();
-                if (path == null || !path.startsWith("/") || FileBackend.isInDirectoryThatShouldNotBeScanned(getActivity(), path)) {
+                final String path = m.getRelativeFilePath();
+                if (path == null || !path.startsWith("/")) {
                     deleteFile.setVisible(true);
                     deleteFile.setTitle(activity.getString(R.string.delete_x_file, UIHelper.getFileDescriptionString(activity, m)));
                 }

src/main/java/eu/siacs/conversations/ui/RecordingActivity.java 🔗

@@ -6,6 +6,7 @@ import android.content.Intent;
 import android.media.MediaRecorder;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.FileObserver;
 import android.os.Handler;
 import android.os.SystemClock;
@@ -153,28 +154,21 @@ public class RecordingActivity extends Activity implements View.OnClickListener
         }
     }
 
-    private static File generateOutputFilename(Context context) {
+    private File generateOutputFilename() {
         final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US);
         final String filename = "RECORDING_" + dateFormat.format(new Date()) + ".m4a";
-        return new File(FileBackend.getLegacyStorageLocation(context, STORAGE_DIRECTORY_TYPE_NAME), filename);
+        //TODO once we target 31 use DIRECTORY_RECORDINGS
+        final File parentDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+        final File conversationsDirectory = new File(parentDirectory, getString(R.string.app_name));
+        return new File(conversationsDirectory, filename);
     }
 
     private void setupOutputFile() {
-        mOutputFile = generateOutputFilename(this);
-        File parentDirectory = mOutputFile.getParentFile();
+        mOutputFile = generateOutputFilename();
+        final File parentDirectory = mOutputFile.getParentFile();
         if (parentDirectory.mkdirs()) {
             Log.d(Config.LOGTAG, "created " + parentDirectory.getAbsolutePath());
         }
-        File noMedia = new File(parentDirectory, ".nomedia");
-        if (!noMedia.exists()) {
-            try {
-                if (noMedia.createNewFile()) {
-                    Log.d(Config.LOGTAG, "created nomedia file in " + parentDirectory.getAbsolutePath());
-                }
-            } catch (IOException e) {
-                Log.d(Config.LOGTAG, "unable to create nomedia file in " + parentDirectory.getAbsolutePath(), e);
-            }
-        }
         setupFileObserver(parentDirectory);
     }
 

src/main/java/eu/siacs/conversations/ui/SettingsActivity.java 🔗

@@ -224,7 +224,7 @@ public class SettingsActivity extends XmppActivity implements
 
 		final Preference createBackupPreference = mSettingsFragment.findPreference("create_backup");
 		if (createBackupPreference != null) {
-			createBackupPreference.setSummary(getString(R.string.pref_create_backup_summary, FileBackend.getBackupDirectory(this)));
+			createBackupPreference.setSummary(getString(R.string.pref_create_backup_summary, FileBackend.getBackupDirectory(this).getAbsolutePath()));
 			createBackupPreference.setOnPreferenceClickListener(preference -> {
 				if (hasStoragePermission(REQUEST_CREATE_BACKUP)) {
 					createBackup();