mirror of
https://github.com/M66B/FairEmail.git
synced 2025-03-16 08:59:35 +00:00
Added options to open links, show images and original messages without confirmation
This commit is contained in:
parent
45f46cf852
commit
3768f5c0ee
5 changed files with 137 additions and 24 deletions
25
FAQ.md
25
FAQ.md
|
@ -106,7 +106,6 @@ Related questions:
|
||||||
|
|
||||||
Anything on this list is in random order and *might* be added in the near future.
|
Anything on this list is in random order and *might* be added in the near future.
|
||||||
|
|
||||||
|
|
||||||
## Frequently requested features
|
## Frequently requested features
|
||||||
|
|
||||||
The design is based on many discussions and if you like you can discuss about it [in this forum](https://forum.xda-developers.com/android/apps-games/source-email-t3824168) too.
|
The design is based on many discussions and if you like you can discuss about it [in this forum](https://forum.xda-developers.com/android/apps-games/source-email-t3824168) too.
|
||||||
|
@ -114,22 +113,6 @@ The goal of the design is to be minimalistic (no unnecessary menus, buttons, etc
|
||||||
All displayed things should be useful in one or another way and should be carefully positioned for easy usage.
|
All displayed things should be useful in one or another way and should be carefully positioned for easy usage.
|
||||||
Fonts, sizes, colors, etc should be material design whenever possible.
|
Fonts, sizes, colors, etc should be material design whenever possible.
|
||||||
|
|
||||||
Since FairEmail is privacy oriented, the following will not be added:
|
|
||||||
|
|
||||||
* Opening links without confirmation (if you want to reset the default *Open with* apps, please [see here](https://support.google.com/android/answer/9415055))
|
|
||||||
* Showing images and original messages without confirmation, see also [this FAQ](#user-content-faq35)
|
|
||||||
* Direct file/folder access: for security/privacy reasons (other) apps should use the [Storage Access Framework](https://developer.android.com/guide/topics/providers/document-provider), see also [this FAQ](#user-content-faq49)
|
|
||||||
|
|
||||||
Confirmation is just one tap, which is just a small price for better privacy.
|
|
||||||
You can show images and original messages by default for trusted senders on a case-by-case basis by checking *Do not ask this again for ...*.
|
|
||||||
Note that your contacts could unknowingly send malicious messages if they got infected with malware.
|
|
||||||
|
|
||||||
Stripped and reformatted messages are often better readable than original messages because the margins are removed, and font colors and sizes are standardized.
|
|
||||||
|
|
||||||
FairEmail does not allow other apps access to your messages and attachments without your approval.
|
|
||||||
|
|
||||||
FairEmail follows all the best practices for an email client as described in [this EFF article](https://www.eff.org/deeplinks/2019/01/stop-tracking-my-emails).
|
|
||||||
|
|
||||||
## Frequently Asked Questions
|
## Frequently Asked Questions
|
||||||
|
|
||||||
* [(1) Which permissions are needed and why?](#user-content-faq1)
|
* [(1) Which permissions are needed and why?](#user-content-faq1)
|
||||||
|
@ -1116,10 +1099,16 @@ Note that your contacts could unknowingly send malicious messages if they got in
|
||||||
|
|
||||||
FairEmail formats messages again causing messages to look different from the original, but also uncovering phishing links.
|
FairEmail formats messages again causing messages to look different from the original, but also uncovering phishing links.
|
||||||
|
|
||||||
|
Note that reformatted messages are often better readable than original messages because the margins are removed, and font colors and sizes are standardized.
|
||||||
|
|
||||||
The Gmail app shows images by default by downloading the images through a Google proxy server.
|
The Gmail app shows images by default by downloading the images through a Google proxy server.
|
||||||
Since the images are downloaded from the source server [in real-time](https://blog.filippo.io/how-the-new-gmail-image-proxy-works-and-what-this-means-for-you/),
|
Since the images are downloaded from the source server [in real-time](https://blog.filippo.io/how-the-new-gmail-image-proxy-works-and-what-this-means-for-you/),
|
||||||
this is even less secure because Google is involved too without providing much benefit.
|
this is even less secure because Google is involved too without providing much benefit.
|
||||||
|
|
||||||
|
You can show images and original messages by default for trusted senders on a case-by-case basis by checking *Do not ask this again for ...*.
|
||||||
|
|
||||||
|
If you want to reset the default *Open with* apps, please [see here](https://support.google.com/android/answer/9415055)).
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<a name="faq36"></a>
|
<a name="faq36"></a>
|
||||||
|
@ -2053,7 +2042,9 @@ See also [this FAQ](#user-content-faq92).
|
||||||
|
|
||||||
For privacy and security reasons FairEmail does not have permissions to directly access files,
|
For privacy and security reasons FairEmail does not have permissions to directly access files,
|
||||||
instead the Storage Access Framework, available and recommended since Android 4.4 KitKat (released in 2013), is used to select files.
|
instead the Storage Access Framework, available and recommended since Android 4.4 KitKat (released in 2013), is used to select files.
|
||||||
|
|
||||||
If an app is listed depends on if the app implements a [document provider](https://developer.android.com/guide/topics/providers/document-provider).
|
If an app is listed depends on if the app implements a [document provider](https://developer.android.com/guide/topics/providers/document-provider).
|
||||||
|
If the app is not listed, you might need to ask the developer of the app to add support for the Storage Access Framework.
|
||||||
|
|
||||||
Android Q will make it harder and maybe even impossible to directly access files,
|
Android Q will make it harder and maybe even impossible to directly access files,
|
||||||
see [here](https://developer.android.com/preview/privacy/scoped-storage) and [here](https://www.xda-developers.com/android-q-storage-access-framework-scoped-storage/) for more details.
|
see [here](https://developer.android.com/preview/privacy/scoped-storage) and [here](https://www.xda-developers.com/android-q-storage-access-framework-scoped-storage/) for more details.
|
||||||
|
|
|
@ -1484,6 +1484,14 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean confirm_images = prefs.getBoolean("confirm_images", true);
|
||||||
|
boolean confirm_html = prefs.getBoolean("confirm_html", true);
|
||||||
|
|
||||||
|
if (!confirm_images)
|
||||||
|
properties.setValue("images", message.id, true);
|
||||||
|
if (!confirm_html)
|
||||||
|
properties.setValue("full", message.id, true);
|
||||||
|
|
||||||
boolean show_full = properties.getValue("full", message.id);
|
boolean show_full = properties.getValue("full", message.id);
|
||||||
boolean show_images = properties.getValue("images", message.id);
|
boolean show_images = properties.getValue("images", message.id);
|
||||||
boolean show_quotes = (properties.getValue("quotes", message.id) || !collapse_quotes);
|
boolean show_quotes = (properties.getValue("quotes", message.id) || !collapse_quotes);
|
||||||
|
@ -3389,13 +3397,17 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
||||||
if ("cid".equals(uri.getScheme()) || "data".equals(uri.getScheme()))
|
if ("cid".equals(uri.getScheme()) || "data".equals(uri.getScheme()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
boolean confirm_links = prefs.getBoolean("confirm_links", true);
|
||||||
args.putParcelable("uri", uri);
|
if (confirm_links) {
|
||||||
args.putString("title", title);
|
Bundle args = new Bundle();
|
||||||
|
args.putParcelable("uri", uri);
|
||||||
|
args.putString("title", title);
|
||||||
|
|
||||||
FragmentDialogLink fragment = new FragmentDialogLink();
|
FragmentDialogLink fragment = new FragmentDialogLink();
|
||||||
fragment.setArguments(args);
|
fragment.setArguments(args);
|
||||||
fragment.show(parentFragment.getParentFragmentManager(), "open:link");
|
fragment.show(parentFragment.getParentFragmentManager(), "open:link");
|
||||||
|
} else
|
||||||
|
Helper.view(context, uri, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -63,6 +63,9 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class FragmentOptionsPrivacy extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener {
|
public class FragmentOptionsPrivacy extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
private SwitchCompat swConfirmLinks;
|
||||||
|
private SwitchCompat swConfirmImages;
|
||||||
|
private SwitchCompat swConfirmHtml;
|
||||||
private SwitchCompat swDisableTracking;
|
private SwitchCompat swDisableTracking;
|
||||||
private SwitchCompat swDisplayHidden;
|
private SwitchCompat swDisplayHidden;
|
||||||
private Spinner spEncryptMethod;
|
private Spinner spEncryptMethod;
|
||||||
|
@ -84,6 +87,7 @@ public class FragmentOptionsPrivacy extends FragmentBase implements SharedPrefer
|
||||||
private List<String> openPgpProvider = new ArrayList<>();
|
private List<String> openPgpProvider = new ArrayList<>();
|
||||||
|
|
||||||
private final static String[] RESET_OPTIONS = new String[]{
|
private final static String[] RESET_OPTIONS = new String[]{
|
||||||
|
"confirm_links", "confirm_images", "confirm_html",
|
||||||
"disable_tracking", "display_hidden",
|
"disable_tracking", "display_hidden",
|
||||||
"default_encrypt_method", "openpgp_provider", "autocrypt", "autocrypt_mutual",
|
"default_encrypt_method", "openpgp_provider", "autocrypt", "autocrypt_mutual",
|
||||||
"sign_default", "encrypt_default", "auto_decrypt",
|
"sign_default", "encrypt_default", "auto_decrypt",
|
||||||
|
@ -102,6 +106,9 @@ public class FragmentOptionsPrivacy extends FragmentBase implements SharedPrefer
|
||||||
|
|
||||||
// Get controls
|
// Get controls
|
||||||
|
|
||||||
|
swConfirmLinks = view.findViewById(R.id.swConfirmLinks);
|
||||||
|
swConfirmImages = view.findViewById(R.id.swConfirmImages);
|
||||||
|
swConfirmHtml = view.findViewById(R.id.swConfirmHtml);
|
||||||
swDisableTracking = view.findViewById(R.id.swDisableTracking);
|
swDisableTracking = view.findViewById(R.id.swDisableTracking);
|
||||||
swDisplayHidden = view.findViewById(R.id.swDisplayHidden);
|
swDisplayHidden = view.findViewById(R.id.swDisplayHidden);
|
||||||
spEncryptMethod = view.findViewById(R.id.spEncryptMethod);
|
spEncryptMethod = view.findViewById(R.id.spEncryptMethod);
|
||||||
|
@ -137,6 +144,27 @@ public class FragmentOptionsPrivacy extends FragmentBase implements SharedPrefer
|
||||||
|
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
|
|
||||||
|
swConfirmLinks.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||||
|
prefs.edit().putBoolean("confirm_links", checked).apply();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
swConfirmImages.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||||
|
prefs.edit().putBoolean("confirm_images", checked).apply();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
swConfirmHtml.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||||
|
prefs.edit().putBoolean("confirm_html", checked).apply();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
swDisableTracking.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
swDisableTracking.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||||
|
@ -353,6 +381,9 @@ public class FragmentOptionsPrivacy extends FragmentBase implements SharedPrefer
|
||||||
private void setOptions() {
|
private void setOptions() {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
|
|
||||||
|
swConfirmLinks.setChecked(prefs.getBoolean("confirm_links", true));
|
||||||
|
swConfirmImages.setChecked(prefs.getBoolean("confirm_images", true));
|
||||||
|
swConfirmHtml.setChecked(prefs.getBoolean("confirm_html", true));
|
||||||
swDisableTracking.setChecked(prefs.getBoolean("disable_tracking", true));
|
swDisableTracking.setChecked(prefs.getBoolean("disable_tracking", true));
|
||||||
swDisplayHidden.setChecked(prefs.getBoolean("display_hidden", false));
|
swDisplayHidden.setChecked(prefs.getBoolean("display_hidden", false));
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,81 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/swConfirmLinks"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/title_advanced_confirm_links"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:switchPadding="12dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvConfirmLinksHint"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="48dp"
|
||||||
|
android:text="@string/title_advanced_display_harmful_hint"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
android:textColor="?attr/colorWarning"
|
||||||
|
android:textStyle="italic"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/swConfirmLinks" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/swConfirmImages"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/title_advanced_confirm_images"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tvConfirmLinksHint"
|
||||||
|
app:switchPadding="12dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvConfirmImagesHint"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="48dp"
|
||||||
|
android:text="@string/title_advanced_display_harmful_hint"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
android:textColor="?attr/colorWarning"
|
||||||
|
android:textStyle="italic"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/swConfirmImages" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/swConfirmHtml"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/title_advanced_confirm_html"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tvConfirmImagesHint"
|
||||||
|
app:switchPadding="12dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvConfirmHtmlHint"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="48dp"
|
||||||
|
android:text="@string/title_advanced_display_harmful_hint"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
android:textColor="?attr/colorWarning"
|
||||||
|
android:textStyle="italic"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/swConfirmHtml" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.SwitchCompat
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
android:id="@+id/swDisableTracking"
|
android:id="@+id/swDisableTracking"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -21,7 +96,7 @@
|
||||||
android:text="@string/title_advanced_tracking"
|
android:text="@string/title_advanced_tracking"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toBottomOf="@+id/tvConfirmHtmlHint"
|
||||||
app:switchPadding="12dp" />
|
app:switchPadding="12dp" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.SwitchCompat
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
|
|
@ -373,6 +373,9 @@
|
||||||
<string name="title_advanced_sound">Select notification sound</string>
|
<string name="title_advanced_sound">Select notification sound</string>
|
||||||
<string name="title_advanced_alert_once" translatable="false">MIUI notification sound workaround</string>
|
<string name="title_advanced_alert_once" translatable="false">MIUI notification sound workaround</string>
|
||||||
|
|
||||||
|
<string name="title_advanced_confirm_links">Confirm opening links</string>
|
||||||
|
<string name="title_advanced_confirm_images">Confirm showing images</string>
|
||||||
|
<string name="title_advanced_confirm_html">Show reformatted messages by default</string>
|
||||||
<string name="title_advanced_tracking">Automatically recognize and disable tracking images</string>
|
<string name="title_advanced_tracking">Automatically recognize and disable tracking images</string>
|
||||||
<string name="title_advanced_display_hidden">Display hidden message texts</string>
|
<string name="title_advanced_display_hidden">Display hidden message texts</string>
|
||||||
<string name="title_advanced_encrypt_method">Default encryption method</string>
|
<string name="title_advanced_encrypt_method">Default encryption method</string>
|
||||||
|
@ -447,6 +450,7 @@
|
||||||
<string name="title_advanced_autoclose_hint">Automatically close conversations when all messages are archived, sent or trashed</string>
|
<string name="title_advanced_autoclose_hint">Automatically close conversations when all messages are archived, sent or trashed</string>
|
||||||
<string name="title_advanced_sender_hint">Most providers do not allow modified sender addresses</string>
|
<string name="title_advanced_sender_hint">Most providers do not allow modified sender addresses</string>
|
||||||
|
|
||||||
|
<string name="title_advanced_display_harmful_hint">Disabling this option might be harmful for your privacy</string>
|
||||||
<string name="title_advanced_display_hidden_hint">This can result in odd looking and double texts</string>
|
<string name="title_advanced_display_hidden_hint">This can result in odd looking and double texts</string>
|
||||||
<string name="title_advanced_display_pin_hint">A PIN takes precedence over biometrics authentication</string>
|
<string name="title_advanced_display_pin_hint">A PIN takes precedence over biometrics authentication</string>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue