Removed external attachment storage

pull/214/head
M66B 7 months ago
parent 84deb380dd
commit fbf258fa89

@ -3346,13 +3346,15 @@ Messages, attachments, etc stored on external storage media, like an sdcard, can
See [here](https://developer.android.com/training/data-storage) for the details.
Instead, consider to use [adoptable storage](https://source.android.com/devices/storage/adoptable).
Since version 1.1829 is it possible to store attachments to external storage space private to the app (except for file managers) via an option in the debug panel.
You can enable the debug panel by enabling debug mode in the miscellaneous settings (last option).
To prevent ongoing operations from storing attachments at the old location
you should disable receiving messages in the receive settings and wait until all operations have been completed before changing this option.
Please be aware that removing the storage space will inevitably result in problems, which is one of the reasons why this option is hidden.
~~Since version 1.1829 is it possible to store attachments to external storage space private to the app (except for file managers) via an option in the debug panel.~~
~~You can enable the debug panel by enabling debug mode in the miscellaneous settings (last option).~~
~~To prevent ongoing operations from storing attachments at the old location~~
~~you should disable receiving messages in the receive settings and wait until all operations have been completed before changing this option.~~
~~Please be aware that removing the storage space will inevitably result in problems, which is one of the reasons why this option is hidden.~~
Moving messages to an sdcard is not an option because this would significantly reduce the response times of the app.
~~Moving messages to an sdcard is not an option because this would significantly reduce the response times of the app.~~
The option to move attachments to external storage space was removed in version 1.2137 because Play Store policies considers it unsafe.
When needed you can save (raw) messages via the three-dots menu just above the message text
and save attachments by tapping on the floppy icon.

File diff suppressed because it is too large Load Diff

@ -69,7 +69,7 @@ import javax.mail.internet.InternetAddress;
// https://developer.android.com/topic/libraries/architecture/room.html
@Database(
version = 285,
version = 286,
entities = {
EntityIdentity.class,
EntityAccount.class,
@ -2884,6 +2884,16 @@ public abstract class DB extends RoomDatabase {
logMigration(startVersion, endVersion);
db.execSQL("ALTER TABLE `message` ADD COLUMN `write_below` INTEGER");
}
}).addMigrations(new Migration(285, 286) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
logMigration(startVersion, endVersion);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean external_storage = prefs.getBoolean("external_storage", false);
if (external_storage || BuildConfig.DEBUG)
db.execSQL("UPDATE `attachment` SET available = 0");
prefs.edit().remove("external_storage").apply();
}
}).addMigrations(new Migration(998, 999) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {

@ -172,7 +172,7 @@ public class EntityAttachment {
}
static File getFile(Context context, long id, String name) {
File dir = Helper.ensureExists(new File(getRoot(context), "attachments"));
File dir = Helper.ensureExists(new File(context.getFilesDir(), "attachments"));
String filename = Long.toString(id);
if (!TextUtils.isEmpty(name))
filename += "." + Helper.sanitizeFilename(name);
@ -181,16 +181,6 @@ public class EntityAttachment {
return new File(dir, filename);
}
static File getRoot(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean external_storage = prefs.getBoolean("external_storage", false);
File root = (external_storage
? Helper.getExternalFilesDir(context)
: context.getFilesDir());
return root;
}
static void copy(Context context, long oldid, long newid) {
DB db = DB.getInstance(context);

@ -1186,9 +1186,6 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
continue;
}
if ("external_storage".equals(key))
continue;
if ("reformatted_hint".equals(key))
continue;

@ -168,8 +168,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
private SwitchCompat swAutostart;
private SwitchCompat swEmergency;
private SwitchCompat swWorkManager;
private SwitchCompat swExternalStorage;
private TextView tvExternalStorageFolder;
private SwitchCompat swIntegrity;
private SwitchCompat swWal;
private SwitchCompat swCheckpoints;
@ -272,7 +270,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
"crash_reports", "cleanup_attachments",
"watchdog", "experiments", "main_log", "main_log_memory", "protocol", "log_level", "debug", "leak_canary",
"test1", "test2", "test3", "test4", "test5",
"emergency_file", "work_manager", // "external_storage",
"emergency_file", "work_manager",
"sqlite_integrity_check", "wal", "sqlite_checkpoints", "sqlite_analyze", "sqlite_auto_vacuum", "sqlite_sync_extra", "sqlite_cache",
"chunk_size", "thread_range",
"autoscroll_editor", "undo_manager",
@ -405,8 +403,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swAutostart = view.findViewById(R.id.swAutostart);
swEmergency = view.findViewById(R.id.swEmergency);
swWorkManager = view.findViewById(R.id.swWorkManager);
swExternalStorage = view.findViewById(R.id.swExternalStorage);
tvExternalStorageFolder = view.findViewById(R.id.tvExternalStorageFolder);
swIntegrity = view.findViewById(R.id.swIntegrity);
swWal = view.findViewById(R.id.swWal);
swCheckpoints = view.findViewById(R.id.swCheckpoints);
@ -1088,59 +1084,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
}
});
swExternalStorage.setEnabled(Helper.getExternalFilesDir(getContext()) != null);
swExternalStorage.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("external_storage", isChecked);
editor.apply();
Bundle args = new Bundle();
args.putBoolean("external_storage", isChecked);
new SimpleTask<Integer>() {
@Override
protected Integer onExecute(Context context, Bundle args) throws IOException {
boolean external_storage = args.getBoolean("external_storage");
File sourceRoot = (!external_storage
? Helper.getExternalFilesDir(context)
: context.getFilesDir());
File targetRoot = (external_storage
? Helper.getExternalFilesDir(context)
: context.getFilesDir());
File source = Helper.ensureExists(new File(sourceRoot, "attachments"));
File target = Helper.ensureExists(new File(targetRoot, "attachments"));
File[] attachments = source.listFiles();
if (attachments != null)
for (File attachment : attachments) {
File dest = new File(target, attachment.getName());
Log.i("Move " + attachment + " to " + dest);
Helper.copy(attachment, dest);
Helper.secureDelete(attachment);
}
return (attachments == null ? -1 : attachments.length);
}
@Override
protected void onExecuted(Bundle args, Integer count) {
String msg = String.format("Moved %d attachments", count);
ToastEx.makeText(getContext(), msg, Toast.LENGTH_LONG).show();
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentOptionsMisc.this, args, "external");
}
});
swIntegrity.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton v, boolean checked) {
@ -1984,11 +1927,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
else
tvLastDaily.setText(("-"));
File external = Helper.getExternalFilesDir(getContext());
boolean emulated = (external != null && Environment.isExternalStorageEmulated(external));
tvExternalStorageFolder.setText(
(external == null ? null : external.getAbsolutePath()) + (emulated ? " emulated" : ""));
swExactAlarms.setEnabled(AlarmManagerCompatEx.canScheduleExactAlarms(getContext()));
swTestIab.setVisibility(BuildConfig.DEBUG && BuildConfig.TEST_RELEASE ? View.VISIBLE : View.GONE);
@ -2276,7 +2214,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swAutostart.setChecked(Helper.isComponentEnabled(getContext(), ReceiverAutoStart.class));
swEmergency.setChecked(prefs.getBoolean("emergency_file", true));
swWorkManager.setChecked(prefs.getBoolean("work_manager", true));
swExternalStorage.setChecked(prefs.getBoolean("external_storage", false));
swIntegrity.setChecked(prefs.getBoolean("sqlite_integrity_check", true));
swWal.setChecked(prefs.getBoolean("wal", true));

@ -3455,9 +3455,12 @@ public class Log {
if (ai != null)
size += write(os, String.format("Source: %s\r\n public: %s\r\n",
ai.sourceDir, ai.publicSourceDir));
size += write(os, String.format("Files: %s\r\n external: %s\r\n storage: %s\r\n",
context.getFilesDir(), Helper.getExternalFilesDir(context),
File external = Helper.getExternalFilesDir(context);
boolean emulated = (external != null && Environment.isExternalStorageEmulated(external));
size += write(os, String.format("Files: %s\r\n external: %s\r\n emulated: %b\r\n storage: %s\r\n",
context.getFilesDir(), external, emulated,
Environment.getExternalStorageDirectory()));
size += write(os, String.format("Cache: %s\r\n external: %s\n",
context.getCacheDir(), context.getExternalCacheDir()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)

@ -260,7 +260,7 @@ public class WorkerCleanup extends Worker {
// Cleanup attachment files
{
Log.breadcrumb("worker", "cleanup", "attachment files");
File[] attachments = new File(EntityAttachment.getRoot(context), "attachments").listFiles();
File[] attachments = new File(context.getFilesDir(), "attachments").listFiles();
if (attachments != null)
for (File file : attachments)
if (manual || file.lastModified() + KEEP_FILES_DURATION < now)

@ -997,32 +997,6 @@
app:layout_constraintTop_toBottomOf="@id/swEmergency"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swExternalStorage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:drawableStart="@drawable/twotone_warning_24"
android:drawablePadding="6dp"
android:text="@string/title_advanced_external_storage"
app:drawableTint="?attr/colorWarning"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swWorkManager"
app:switchPadding="12dp" />
<TextView
android:id="@+id/tvExternalStorageFolder"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:text="/data/data/..."
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swExternalStorage" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swIntegrity"
android:layout_width="0dp"
@ -1032,7 +1006,7 @@
android:text="@string/title_advanced_integrity"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvExternalStorageFolder"
app:layout_constraintTop_toBottomOf="@id/swWorkManager"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat

@ -882,7 +882,6 @@
<string name="title_advanced_autostart" translatable="false">Autostart app</string>
<string name="title_advanced_emergency" translatable="false">Write emergency file</string>
<string name="title_advanced_work_manager" translatable="false">Initialize work manager</string>
<string name="title_advanced_external_storage" translatable="false">Use external storage</string>
<string name="title_advanced_integrity" translatable="false">sqlite integrity check</string>
<string name="title_advanced_wal" translatable="false">sqlite WAL</string>
<string name="title_advanced_checkpoints" translatable="false">sqlite checkpoints</string>

@ -1753,8 +1753,9 @@ Y1 OK CAPABILITY completed</code></pre>
<p>FairEmail uses services and alarms, provides widgets and listens for the boot completed event to be started on device start, so it is not possible to store the app on external storage media, like an sdcard. See also <a href="https://developer.android.com/guide/topics/data/install-location">here</a>.</p>
<p>Since the app is small anyway and the data files will be stored in the same place, the benefit would be limited anyway.</p>
<p>Messages, attachments, etc stored on external storage media, like an sdcard, can be accessed by other apps and is therefore not safe. See <a href="https://developer.android.com/training/data-storage">here</a> for the details. Instead, consider to use <a href="https://source.android.com/devices/storage/adoptable">adoptable storage</a>.</p>
<p>Since version 1.1829 is it possible to store attachments to external storage space private to the app (except for file managers) via an option in the debug panel. You can enable the debug panel by enabling debug mode in the miscellaneous settings (last option). To prevent ongoing operations from storing attachments at the old location you should disable receiving messages in the receive settings and wait until all operations have been completed before changing this option. Please be aware that removing the storage space will inevitably result in problems, which is one of the reasons why this option is hidden.</p>
<p>Moving messages to an sdcard is not an option because this would significantly reduce the response times of the app.</p>
<p><del>Since version 1.1829 is it possible to store attachments to external storage space private to the app (except for file managers) via an option in the debug panel.</del> <del>You can enable the debug panel by enabling debug mode in the miscellaneous settings (last option).</del> <del>To prevent ongoing operations from storing attachments at the old location</del> <del>you should disable receiving messages in the receive settings and wait until all operations have been completed before changing this option.</del> <del>Please be aware that removing the storage space will inevitably result in problems, which is one of the reasons why this option is hidden.</del></p>
<p><del>Moving messages to an sdcard is not an option because this would significantly reduce the response times of the app.</del></p>
<p>The option to move attachments to external storage space was removed in version 1.2137 because Play Store policies considers it unsafe.</p>
<p>When needed you can save (raw) messages via the three-dots menu just above the message text and save attachments by tapping on the floppy icon.</p>
<p>If you need to save on storage space, you can limit the number of days messages are being synchronized and kept on your device and disable downloading and storing of message texts and attachments (which means only message headers will be stored). You can change these settings by long pressing a folder in the folder list and selecting <em>Edit properties</em>.</p>
<p><br /></p>

Loading…
Cancel
Save