Show tracking pixel icon

pull/162/head
M66B 5 years ago
parent c7dee255f4
commit f8c2a00557

@ -1691,8 +1691,9 @@ You'll likely want to disabled [browse on server](#user-content-faq24) too.
Please see [here](https://en.wikipedia.org/wiki/Web_beacon) about what a tracking image exactly is.
In short tracking images keep track if you opened a message.
FairEmail automatically recognizes images with a surface of less than or equal to 25 pixels as tracking images.
FairEmail automatically removes the link of such images, which makes such images appear as broken, and adds a remark about this below the image.
FairEmail will in most cases automatically recognize tracking images and replace them by this icon:
![External image](https://raw.githubusercontent.com/google/material-design-icons/master/maps/1x_web/ic_my_location_black_48dp.png)
Automatic recognition of tracking images can be disabled in the behavior settings.

@ -1468,6 +1468,14 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
if (disable_tracking)
HtmlHelper.removeTrackingPixels(context, document);
if (debug) {
Document format = JsoupEx.parse(document.html());
format.outputSettings().prettyPrint(true).outline(true).indentAmount(1);
Element pre = document.createElement("pre");
pre.text(format.html());
document.body().appendChild(pre);
}
return document.html();
} else {
// Collapse quotes
@ -2511,13 +2519,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
full ? R.layout.dialog_show_full : R.layout.dialog_show_images, null);
CheckBox cbNotAgain = dview.findViewById(R.id.cbNotAgain);
if (!full) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean disable_tracking = prefs.getBoolean("disable_tracking", true);
TextView tvTracking = dview.findViewById(R.id.tvTracking);
tvTracking.setVisibility(disable_tracking ? View.VISIBLE : View.GONE);
}
if (message.from == null || message.from.length == 0)
cbNotAgain.setVisibility(View.GONE);
else {
@ -2541,6 +2542,23 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
}
});
if (!full) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean disable_tracking = prefs.getBoolean("disable_tracking", true);
ImageView ivInfo = dview.findViewById(R.id.ivInfo);
Group grpTracking = dview.findViewById(R.id.grpTracking);
grpTracking.setVisibility(disable_tracking ? View.VISIBLE : View.GONE);
ivInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.viewFAQ(context, 82);
}
});
}
// TODO: dialog fragment
final Dialog dialog = new AlertDialog.Builder(context)
.setView(dview)

@ -21,7 +21,10 @@ package eu.faircode.email;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.text.Html;
@ -33,6 +36,7 @@ import android.util.Base64;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.text.HtmlCompat;
import androidx.core.util.PatternsCompat;
import androidx.preference.PreferenceManager;
@ -47,6 +51,7 @@ import org.jsoup.safety.Whitelist;
import org.jsoup.select.NodeTraversor;
import org.jsoup.select.NodeVisitor;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@ -470,6 +475,24 @@ public class HtmlHelper {
}
static void removeTrackingPixels(Context context, Document document) {
Drawable d = ContextCompat.getDrawable(context, R.drawable.baseline_my_location_24);
d.setTint(Helper.resolveColor(context, R.attr.colorWarning));
Bitmap bm = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
d.setBounds(0, 0, c.getWidth(), c.getHeight());
d.draw(c);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, bos);
StringBuilder sb = new StringBuilder();
sb.append("data:");
sb.append("image/png");
sb.append(";base64,");
sb.append(Base64.encodeToString(bos.toByteArray(), Base64.DEFAULT));
boolean dark = Helper.isDarkTheme(context);
// Build list of allowed hosts
List<String> hosts = new ArrayList<>();
for (Element img : document.select("img")) {
@ -489,11 +512,11 @@ public class HtmlHelper {
Uri uri = Uri.parse(img.attr("src"));
String host = uri.getHost();
if (host == null || !hosts.contains(host)) {
img.removeAttr("src");
img.tagName("a");
img.attr("href", src);
img.appendText(context.getString(R.string.title_hint_tracking_image,
img.attr("width"), img.attr("height")));
img.attr("src", sb.toString());
img.attr("alt", context.getString(R.string.title_legend_tracking_pixel));
img.attr("height", "24");
img.attr("width", "24");
img.attr("style", "display: block !important;");
}
}
}

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06C6.83,3.52 3.52,6.83 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L23,13v-2h-2.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
</vector>

@ -20,18 +20,40 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/ivTracking"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/tvTracking"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/tvTracking"
app:srcCompat="@drawable/baseline_my_location_24" />
<TextView
android:id="@+id/tvTracking"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:text="@string/title_ask_show_image_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?android:attr/textColorPrimary"
android:textStyle="italic"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/ivInfo"
app:layout_constraintStart_toEndOf="@id/ivTracking"
app:layout_constraintTop_toBottomOf="@id/tvMessage" />
<ImageButton
android:id="@+id/ivInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
app:layout_constraintBottom_toBottomOf="@+id/tvTracking"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tvTracking"
app:srcCompat="@drawable/baseline_info_24" />
<CheckBox
android:id="@+id/cbNotAgain"
android:layout_width="wrap_content"
@ -41,5 +63,11 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTracking" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpTracking"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="ivTracking,tvTracking,ivInfo" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbWait"
style="@style/Base.Widget.AppCompat.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:padding="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -454,6 +454,28 @@
app:layout_constraintStart_toEndOf="@id/ivEmbeddedImage"
app:layout_constraintTop_toTopOf="@id/ivEmbeddedImage" />
<ImageView
android:id="@+id/ivTrackingPixel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/title_legend_tracking_pixel"
android:padding="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ivEmbeddedImage"
app:srcCompat="@drawable/baseline_my_location_24" />
<TextView
android:id="@+id/tvTrackingPixel"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center_vertical"
android:text="@string/title_legend_tracking_pixel"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintBottom_toBottomOf="@id/ivTrackingPixel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/ivTrackingPixel"
app:layout_constraintTop_toTopOf="@id/ivTrackingPixel" />
<ImageView
android:id="@+id/ivBrokenImage"
android:layout_width="wrap_content"
@ -461,7 +483,7 @@
android:contentDescription="@string/title_legend_broken_image"
android:padding="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ivEmbeddedImage"
app:layout_constraintTop_toBottomOf="@id/ivTrackingPixel"
app:srcCompat="@drawable/baseline_broken_image_24" />
<TextView

@ -774,6 +774,7 @@
<string name="title_legend_download">Download content</string>
<string name="title_legend_external_image">External image placeholder</string>
<string name="title_legend_embedded_image">Embedded image placeholder</string>
<string name="title_legend_tracking_pixel">Tracking pixel</string>
<string name="title_legend_broken_image">Broken image</string>
<string name="title_legend_pick">Pick contact</string>
@ -816,8 +817,6 @@
<string name="title_hint_message_actions">Swipe left to trash; Swipe right to archive (if available); The swipe actions can be configured in the account settings</string>
<string name="title_hint_message_selection">Long press a message to start selecting multiple messages; Hold and swipe up or down to select more messages</string>
<string name="title_hint_sync">Downloading messages can take some time, depending on the speed of the provider, internet connection and device and on the number of messages. While downloading messages the app might respond slower.</string>
<string name="title_hint_image_link">Image link</string>
<string name="title_hint_tracking_image">Tracking image %1$sx%2$s</string>
<string name="title_hint_contact_actions">Long press for options</string>
<string name="title_open_link">Open link</string>

Loading…
Cancel
Save