~singpolyma/cheogram-android

8abacd23e8d29a75d0abd497dc842de4663e2a84 — Daniel Gultsch 2 years ago 6061761
use new storage location for backup and recordings
M src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java => src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java +7 -4
@@ 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")) {

M src/main/java/eu/siacs/conversations/persistance/FileBackend.java => src/main/java/eu/siacs/conversations/persistance/FileBackend.java +40 -71
@@ 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 {

M src/main/java/eu/siacs/conversations/services/ExportBackupService.java => src/main/java/eu/siacs/conversations/services/ExportBackupService.java +3 -3
@@ 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);

M src/main/java/eu/siacs/conversations/ui/ConversationFragment.java => src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +2 -2
@@ 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)));
                }

M src/main/java/eu/siacs/conversations/ui/RecordingActivity.java => src/main/java/eu/siacs/conversations/ui/RecordingActivity.java +8 -14
@@ 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);
    }


M src/main/java/eu/siacs/conversations/ui/SettingsActivity.java => src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +1 -1
@@ 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();